diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/canvas.cpp | 5 | ||||
-rw-r--r-- | client/canvas.h | 143 | ||||
-rw-r--r-- | client/display_channel.cpp | 342 | ||||
-rw-r--r-- | client/display_channel.h | 31 | ||||
-rw-r--r-- | client/red_cairo_canvas.cpp | 5 | ||||
-rw-r--r-- | client/red_cairo_canvas.h | 2 | ||||
-rw-r--r-- | client/red_gdi_canvas.cpp | 6 | ||||
-rw-r--r-- | client/red_gdi_canvas.h | 2 | ||||
-rw-r--r-- | client/red_gl_canvas.cpp | 5 | ||||
-rw-r--r-- | client/red_gl_canvas.h | 2 |
10 files changed, 439 insertions, 104 deletions
diff --git a/client/canvas.cpp b/client/canvas.cpp index ba446c9a..b72aad5d 100644 --- a/client/canvas.cpp +++ b/client/canvas.cpp @@ -22,11 +22,12 @@ Canvas::Canvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window) + GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces) : _canvas (NULL) , _pixmap_cache (pixmap_cache) , _palette_cache (palette_cache) , _glz_decoder(glz_decoder_window, _glz_handler, _glz_debug) + , _csurfaces(csurfaces) { } @@ -65,6 +66,8 @@ void Canvas::localalize_image(SPICE_ADDRESS* in_bitmap) localalize_ptr(in_bitmap); image = (SpiceImageDescriptor*)SPICE_GET_ADDRESS(*in_bitmap); switch (image->type) { + case SPICE_IMAGE_TYPE_SURFACE: + break; case SPICE_IMAGE_TYPE_BITMAP: { SpiceBitmapImage *bitmap = (SpiceBitmapImage *)image; localalize_ptr(&bitmap->bitmap.data); diff --git a/client/canvas.h b/client/canvas.h index 8e3a8f1b..1e251edf 100644 --- a/client/canvas.h +++ b/client/canvas.h @@ -36,6 +36,102 @@ enum CanvasType { CANVAS_TYPE_GDI, }; +template <class T, int HASH_SIZE, class Base = EmptyBase> +class CHash : public Base { +public: + CHash() + { + memset(_hash, 0, sizeof(_hash)); + } + + ~CHash() + { + } + + void add(uint32_t id, T* data) + { + Item** item = &_hash[key(id)]; + + while (*item) { + PANIC_ON((*item)->id == id); + item = &(*item)->next; + } + *item = new Item(id, data); + } + + bool is_present(uint32_t id) + { + Item* item = _hash[key(id)]; + + for (;;) { + if (!item) { + return false; + } + + if (item->id != id) { + item = item->next; + continue; + } + + return true; + } + } + + T* get(uint32_t id) + { + Item* item = _hash[key(id)]; + + for (;;) { + PANIC_ON(!item); + + if (item->id != id) { + item = item->next; + continue; + } + + return item->data; + } + } + + void remove(uint32_t id) + { + Item** item = &_hash[key(id)]; + + while (*item) { + if ((*item)->id == id) { + Item *rm_item = *item; + *item = rm_item->next; + delete rm_item; + return; + } + item = &(*item)->next; + } + THROW("id %lu, not found", id); + } + +private: + inline uint32_t key(uint32_t id) {return id % HASH_SIZE;} + +private: + class Item { + public: + Item(uint32_t in_id, T* data) + : id (in_id) + , next (NULL) + , data (data) {} + + ~Item() + { + } + + uint64_t id; + Item* next; + T* data; + }; + + Item* _hash[HASH_SIZE]; +}; + class PixmapCacheTreat { public: static inline pixman_image_t *get(pixman_image_t *surf) @@ -81,6 +177,45 @@ public: } }; +class SpiceImageSurfacesBase; + +typedef CHash<SpiceCanvas, 1024, SpiceImageSurfacesBase> CSurfaces; + +class SpiceImageSurfacesBase { +public: + SpiceImageSurfaces base; + + static void op_put(SpiceImageSurfaces *c, uint32_t surface_id, SpiceCanvas *surface) + { + CSurfaces* cache = reinterpret_cast<CSurfaces*>(c); + cache->add(surface_id, surface); + } + + static SpiceCanvas* op_get(SpiceImageSurfaces *s, uint32_t surface_id) + { + CSurfaces* cache = reinterpret_cast<CSurfaces*>(s); + return cache->get(surface_id); + } + + static void op_del(SpiceImageSurfaces *c, uint32_t surface_id) + { + CSurfaces* cache = reinterpret_cast<CSurfaces*>(c); + cache->remove(surface_id); + } + + SpiceImageSurfacesBase() + { + static SpiceImageSurfacesOps cache_ops = { + op_get + }; + base.ops = &cache_ops; + } +}; + +class Canvas; + +typedef CHash<Canvas, 1024, SpiceImageSurfacesBase> CCanvases; + class CachedPalette { public: CachedPalette(SpicePalette* palette) @@ -241,7 +376,7 @@ public: class Canvas { public: Canvas(PixmapCache& bits_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window); + GlzDecoderWindow &glz_decoder_window, CSurfaces& csurfaces); virtual ~Canvas(); virtual void copy_pixels(const QRegion& region, RedDrawable* dc, @@ -274,11 +409,14 @@ public: virtual CanvasType get_pixmap_type() { return CANVAS_TYPE_INVALID; } + virtual SpiceCanvas *get_internal_canvas() { return _canvas; } + protected: virtual void touched_bbox(const SpiceRect *bbox) {}; PixmapCache& pixmap_cache() { return _pixmap_cache;} PaletteCache& palette_cache() { return _palette_cache;} + CSurfaces& csurfaces() { return _csurfaces; } GlzDecoder& glz_decoder() {return _glz_decoder;} @@ -293,6 +431,7 @@ private: protected: SpiceCanvas* _canvas; + CSurfaces _surfaces; private: PixmapCache& _pixmap_cache; @@ -302,6 +441,8 @@ private: GlzDecoderCanvasDebug _glz_debug; GlzDecoder _glz_decoder; + CSurfaces& _csurfaces; + unsigned long _base; unsigned long _max; }; diff --git a/client/display_channel.cpp b/client/display_channel.cpp index 0d9d20c8..d63726cd 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -59,7 +59,7 @@ public: Application* app = (Application*)events_loop.get_owner(); _channel.screen()->lock_size(); _channel.screen()->resize(_width, _height); - _channel.create_canvas(app->get_canvas_types(), _width, _height, _depth); + _channel.create_canvas(0, app->get_canvas_types(), _width, _height, _depth); } private: @@ -78,13 +78,56 @@ public: virtual void do_response(AbstractProcessLoop& events_loop) { - _channel.destroy_canvas(); + _channel.destroy_canvas(0); } private: DisplayChannel& _channel; }; +class CreateSurfaceEvent: public SyncEvent { +public: + CreateSurfaceEvent(DisplayChannel& channel, int surface_id, int width, int height, int depth) + : _channel (channel) + , _surface_id (surface_id) + , _width (width) + , _height (height) + , _depth (depth) + { + } + + virtual void do_response(AbstractProcessLoop& events_loop) + { + Application* app = (Application*)events_loop.get_owner(); + _channel.create_canvas(_surface_id, app->get_canvas_types(), _width, _height, _depth); + } + +private: + DisplayChannel& _channel; + int _surface_id; + int _width; + int _height; + int _depth; +}; + +class DestroySurfaceEvent: public SyncEvent { +public: + DestroySurfaceEvent(DisplayChannel& channel, int surface_id) + : _channel (channel) + , _surface_id (surface_id) + { + } + + virtual void do_response(AbstractProcessLoop& events_loop) + { + _channel.destroy_canvas(_surface_id); + } + +private: + DisplayChannel& _channel; + int _surface_id; +}; + class UnlockScreenEvent: public Event { public: UnlockScreenEvent(RedScreen* screen) @@ -633,6 +676,42 @@ void ResetTimer::response(AbstractProcessLoop& events_loop) _client.deactivate_interval_timer(this); } +void DisplaySurfacesManger::add_surface(int surface_id, SpiceCanvas *surface) +{ + surfaces.add(surface_id, surface); +} + +void DisplaySurfacesManger::del_surface(int surface_id) +{ + surfaces.remove(surface_id); +} + +void DisplaySurfacesManger::add_canvas(int surface_id, Canvas *canvas) +{ + canvases.add(surface_id, canvas); +} + +void DisplaySurfacesManger::del_canvas(int surface_id) +{ + canvases.remove(surface_id); +} + +CSurfaces& DisplaySurfacesManger::get_surfaces() +{ + return surfaces; +} + +bool DisplaySurfacesManger::is_present_canvas(int surface_id) +{ + + return canvases.is_present(surface_id); +} + +Canvas* DisplaySurfacesManger::get_canvas(int surface_id) +{ + return canvases.get(surface_id); +} + class DisplayHandler: public MessageHandlerImp<DisplayChannel, SPICE_MSG_END_DISPLAY> { public: DisplayHandler(DisplayChannel& channel) @@ -644,7 +723,6 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id, : RedChannel(client, SPICE_CHANNEL_DISPLAY, id, new DisplayHandler(*this), Platform::PRIORITY_LOW) , ScreenLayer (SCREEN_LAYER_DISPLAY, true) - , _canvas (NULL) , _pixmap_cache (pixmap_cache) , _glz_window (glz_window) , _mark (false) @@ -706,6 +784,8 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id, get_process_loop().add_trigger(_gl_interrupt_recreate); #endif get_process_loop().add_trigger(_interrupt_update); + + set_draw_handlers(); } DisplayChannel::~DisplayChannel() @@ -714,7 +794,7 @@ DisplayChannel::~DisplayChannel() screen()->set_update_interrupt_trigger(NULL); } - destroy_canvas(); + //destroy_canvas(); fixme destroy all destroy_strams(); } @@ -786,33 +866,40 @@ void DisplayChannel::clear_draw_handlers() void DisplayChannel::copy_pixels(const QRegion& dest_region, const PixmapHeader &dest_pixmap) { - if (!_canvas.get()) { + Canvas *canvas; + + if (!surfaces_mngr.is_present_canvas(0)) { return; } - _canvas->copy_pixels(dest_region, NULL, &dest_pixmap); + canvas = surfaces_mngr.get_canvas(0); + canvas->copy_pixels(dest_region, NULL, &dest_pixmap); } #ifdef USE_OGL void DisplayChannel::recreate_ogl_context_interrupt() { - Canvas* canvas = _canvas.release(); - if (canvas) { + Canvas* canvas; + + if (surfaces_mngr.is_present_canvas(0)) { //fix me to all surfaces + canvas = surfaces_mngr.get_canvas(0); ((GCanvas *)(canvas))->touch_context(); ((GCanvas *)canvas)->textures_lost(); delete canvas; } - if (!create_ogl_canvas(_x_res, _y_res, _depth, 0, _rendertype)) { + if (!create_ogl_canvas(0, _x_res, _y_res, _depth, 0, _rendertype)) { THROW("create_ogl_canvas failed"); } - ((GCanvas *)(_canvas.get()))->touch_context(); + canvas = surfaces_mngr.get_canvas(0); + ((GCanvas *)(canvas))->touch_context(); } void DisplayChannel::recreate_ogl_context() { - if (_canvas.get() && _canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + if (surfaces_mngr.is_present_canvas(0) && surfaces_mngr.get_canvas(0)->get_pixmap_type() == + CANVAS_TYPE_GL) { if (!screen()->need_recreate_context_gl()) { _gl_interrupt_recreate.trigger(); } @@ -947,21 +1034,25 @@ void DisplayChannel::set_capture_mode(bool on) void DisplayChannel::update_interrupt() { - if (!_canvas.get() || !screen()) { + Canvas *canvas; + + if (!surfaces_mngr.is_present_canvas(0) || !screen()) { return; } + canvas = surfaces_mngr.get_canvas(0); + #ifdef USE_OGL - if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { - ((GCanvas *)(_canvas.get()))->pre_gl_copy(); + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(canvas))->pre_gl_copy(); } #endif screen()->update(); #ifdef USE_OGL - if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { - ((GCanvas *)(_canvas.get()))->post_gl_copy(); + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(canvas))->post_gl_copy(); } #endif } @@ -975,7 +1066,7 @@ void DisplayChannel::pre_migrate() void DisplayChannel::post_migrate() { #ifdef USE_OGL - if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + if (surfaces_mngr.get_canvas(0)->get_pixmap_type() == CANVAS_TYPE_GL) { _gl_interrupt_recreate.trigger(); } #endif @@ -986,11 +1077,15 @@ void DisplayChannel::post_migrate() void DisplayChannel::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) { - if (!_canvas.get()) { + Canvas *canvas; + + if (!surfaces_mngr.is_present_canvas(0)) { return; } - _canvas->copy_pixels(dest_region, dest_dc); + canvas = surfaces_mngr.get_canvas(0); + + canvas->copy_pixels(dest_region, dest_dc); } class ActivateTimerEvent: public Event { @@ -1095,8 +1190,11 @@ void DisplayChannel::on_connect() void DisplayChannel::on_disconnect() { - if (_canvas.get()) { - _canvas->clear(); + if (surfaces_mngr.is_present_canvas(0)) { + Canvas *canvas; + + canvas = surfaces_mngr.get_canvas(0); + canvas->clear(); } if (screen()) { @@ -1116,13 +1214,17 @@ void DisplayChannel::on_disconnect() (*sync_event)->wait(); } -bool DisplayChannel::create_cairo_canvas(int width, int height, int depth) +bool DisplayChannel::create_cairo_canvas(int surface_id, int width, int height, int depth) { try { - std::auto_ptr<CCanvas> canvas(new CCanvas(_pixmap_cache, _palette_cache, _glz_window)); + CCanvas *canvas = new CCanvas(_pixmap_cache, _palette_cache, _glz_window, + surfaces_mngr.get_surfaces()); canvas->set_mode(width, height, depth, screen()->get_window()); - _canvas.reset(canvas.release()); - LOG_INFO("display %d: using cairo", get_id()); + surfaces_mngr.add_canvas(surface_id, canvas); + surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas()); + if (surface_id == 0) { + LOG_INFO("display %d: using cairo", get_id()); + } } catch (...) { return false; } @@ -1130,29 +1232,29 @@ bool DisplayChannel::create_cairo_canvas(int width, int height, int depth) } #ifdef USE_OGL -bool DisplayChannel::create_ogl_canvas(int width, int height, int depth, +bool DisplayChannel::create_ogl_canvas(int surface_id, int width, int height, int depth, bool recreate, RenderType rendertype) { try { RedWindow *win; - int ret = 1; - std::auto_ptr<GCanvas> canvas(new GCanvas(_pixmap_cache, - _palette_cache, - _glz_window)); + GCanvas *canvas = new GCanvas(_pixmap_cache, + _palette_cache, + _glz_window, + surfaces_mngr.get_surfaces()); win = screen()->get_window(); - if (!ret) { - return false; - } canvas->set_mode(width, height, depth, win, rendertype); screen()->untouch_context(); - _canvas.reset(canvas.release()); + surfaces_mngr.add_canvas(surface_id, canvas); + surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas()); _rendertype = rendertype; - LOG_INFO("display %d: using ogl", get_id()); + if (surface_id == 0) { + LOG_INFO("display %d: using ogl", get_id()); + } } catch (...) { return false; } @@ -1162,14 +1264,17 @@ bool DisplayChannel::create_ogl_canvas(int width, int height, int depth, #endif #ifdef WIN32 -bool DisplayChannel::create_gdi_canvas(int width, int height, int depth) +bool DisplayChannel::create_gdi_canvas(int surface_id, int width, int height, int depth) { try { - std::auto_ptr<GDICanvas> canvas( - new GDICanvas(_pixmap_cache, _palette_cache, _glz_window)); + GDICanvas *canvas = new GDICanvas(_pixmap_cache, _palette_cache, _glz_window, + surfaces_mngr.get_surfaces()); canvas->set_mode(width, height, depth); - _canvas.reset(canvas.release()); - LOG_INFO("display %d: using gdi", get_id()); + surfaces_mngr.add_canvas(surface_id, canvas); + surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas()); + if (surface_id == 0) { + LOG_INFO("display %d: using gdi", get_id()); + } } catch (...) { return false; } @@ -1178,21 +1283,29 @@ bool DisplayChannel::create_gdi_canvas(int width, int height, int depth) #endif -void DisplayChannel::destroy_canvas() +void DisplayChannel::destroy_canvas(int surface_id) { - Canvas* canvas = _canvas.release(); + Canvas *canvas; + + if (!surfaces_mngr.is_present_canvas(surface_id)) { + return; + } + + canvas = surfaces_mngr.get_canvas(surface_id); - if (canvas) { #ifdef USE_OGL - if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { - ((GCanvas *)(canvas))->touch_context(); - } -#endif - delete canvas; + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(canvas))->touch_context(); } +#endif + + surfaces_mngr.del_canvas(surface_id); + surfaces_mngr.del_surface(surface_id); + + delete canvas; } -void DisplayChannel::create_canvas(const std::vector<int>& canvas_types, int width, +void DisplayChannel::create_canvas(int surface_id, const std::vector<int>& canvas_types, int width, int height, int depth) { #ifdef USE_OGL @@ -1200,8 +1313,6 @@ void DisplayChannel::create_canvas(const std::vector<int>& canvas_types, int wid #endif unsigned int i; - clear_draw_handlers(); - #ifdef USE_OGL if (screen()->need_recreate_context_gl()) { recreate = false; @@ -1212,23 +1323,23 @@ void DisplayChannel::create_canvas(const std::vector<int>& canvas_types, int wid for (i = 0; i < canvas_types.size(); i++) { - if (canvas_types[i] == CANVAS_OPTION_CAIRO && create_cairo_canvas(width, height, depth)) { + if (canvas_types[i] == CANVAS_OPTION_CAIRO && create_cairo_canvas(surface_id, width, height, depth)) { break; } #ifdef USE_OGL - if (canvas_types[i] == CANVAS_OPTION_OGL_FBO && create_ogl_canvas(width, height, depth, + if (canvas_types[i] == CANVAS_OPTION_OGL_FBO && create_ogl_canvas(surface_id, width, height, depth, recreate, RENDER_TYPE_FBO)) { break; } - if (canvas_types[i] == CANVAS_OPTION_OGL_PBUFF && create_ogl_canvas(width, height, depth, + if (canvas_types[i] == CANVAS_OPTION_OGL_PBUFF && create_ogl_canvas(surface_id, width, height, depth, recreate, RENDER_TYPE_PBUFF)) { break; } #endif #ifdef WIN32 - if (canvas_types[i] == CANVAS_OPTION_GDI && create_gdi_canvas(width, height, depth)) { + if (canvas_types[i] == CANVAS_OPTION_GDI && create_gdi_canvas(surface_id, width, height, depth)) { break; } #endif @@ -1237,8 +1348,6 @@ void DisplayChannel::create_canvas(const std::vector<int>& canvas_types, int wid if (i == canvas_types.size()) { THROW("create canvas failed"); } - - set_draw_handlers(); } void DisplayChannel::handle_mark(RedPeer::InMessage *message) @@ -1258,8 +1367,10 @@ void DisplayChannel::handle_reset(RedPeer::InMessage *message) { screen()->set_update_interrupt_trigger(NULL); - if (_canvas.get()) { - _canvas->clear(); + if (surfaces_mngr.is_present_canvas(0)) { + Canvas *canvas; + canvas = surfaces_mngr.get_canvas(0); + canvas->clear(); } AutoRef<ResetTimer> reset_timer(new ResetTimer(screen()->ref(), get_client())); @@ -1341,8 +1452,8 @@ void DisplayChannel::set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_re void DisplayChannel::handle_stream_create(RedPeer::InMessage* message) { SpiceMsgDisplayStreamCreate* stream_create = (SpiceMsgDisplayStreamCreate*)message->data(); + int surface_id = stream_create->surface_id; - PANIC_ON(stream_create->surface_id != 0); Lock lock(_streams_lock); if (_streams.size() <= stream_create->id) { _streams.resize(stream_create->id + 1); @@ -1357,7 +1468,7 @@ void DisplayChannel::handle_stream_create(RedPeer::InMessage* message) set_clip_rects(stream_create->clip, num_clip_rects, clip_rects, (unsigned long)message->data(), (uint8_t*)(stream_create + 1), message->data() + message->size()); - _streams[stream_create->id] = new VideoStream(get_client(), *_canvas.get(), + _streams[stream_create->id] = new VideoStream(get_client(), *surfaces_mngr.get_canvas(surface_id), *this, stream_create->codec_type, !!(stream_create->flags & SPICE_STREAM_FLAGS_TOP_DOWN), stream_create->stream_width, @@ -1443,6 +1554,7 @@ void DisplayChannel::handle_stream_destroy_all(RedPeer::InMessage* message) void DisplayChannel::create_primary_surface(int width, int height, int depth) { + Canvas *canvas; _mark = false; attach_to_screen(get_client().get_application(), get_id()); clear_area(); @@ -1459,21 +1571,47 @@ void DisplayChannel::create_primary_surface(int width, int height, int depth) _y_res = height; _depth = depth; + canvas = surfaces_mngr.get_canvas(0); + #ifdef USE_OGL - if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { - ((GCanvas *)(_canvas.get()))->touch_context(); + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(canvas))->touch_context(); screen()->set_update_interrupt_trigger(&_interrupt_update); screen()->set_type_gl(); } #endif } +void DisplayChannel::create_surface(int surface_id, int width, int height, int depth) +{ + Canvas *canvas; + + AutoRef<CreateSurfaceEvent> event(new CreateSurfaceEvent(*this, surface_id, width, height, + depth)); + get_client().push_event(*event); + (*event)->wait(); + if (!(*event)->success()) { + THROW("Create surface failed"); + } + + canvas = surfaces_mngr.get_canvas(surface_id); + +#ifdef USE_OGL + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(canvas))->touch_context(); + } +#endif +} + void DisplayChannel::destroy_primary_surface() { #ifdef USE_OGL if (screen()) { - if (_canvas.get()) { - if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + if (surfaces_mngr.is_present_canvas(0)) { + Canvas *canvas; + + canvas = surfaces_mngr.get_canvas(0); + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { screen()->unset_type_gl(); screen()->untouch_context(); } @@ -1481,6 +1619,9 @@ void DisplayChannel::destroy_primary_surface() } #endif + AutoRef<UnlockScreenEvent> unlock_event(new UnlockScreenEvent(screen())); + get_client().push_event(*unlock_event); + AutoRef<DestroyPrimarySurfaceEvent> event(new DestroyPrimarySurfaceEvent(*this)); get_client().push_event(*event); (*event)->wait(); @@ -1489,21 +1630,35 @@ void DisplayChannel::destroy_primary_surface() } } +void DisplayChannel::destroy_surface(int surface_id) +{ + AutoRef<DestroySurfaceEvent> event(new DestroySurfaceEvent(*this, surface_id)); + get_client().push_event(*event); + (*event)->wait(); + if (!(*event)->success()) { + THROW("Destroying surface failed"); + } +} + void DisplayChannel::handle_surface_create(RedPeer::InMessage* message) { SpiceMsgSurfaceCreate* surface_create = (SpiceMsgSurfaceCreate*)message->data(); - PANIC_ON(surface_create->surface_id != 0); - PANIC_ON(surface_create->flags != SPICE_SURFACE_FLAGS_PRIMARY); - - create_primary_surface(surface_create->width, surface_create->height, surface_create->depth); + if (surface_create->flags == SPICE_SURFACE_FLAGS_PRIMARY) { + create_primary_surface(surface_create->width, surface_create->height, surface_create->depth); + } else { + create_surface(surface_create->surface_id, surface_create->width, surface_create->height, + surface_create->depth); + } } void DisplayChannel::handle_surface_destroy(RedPeer::InMessage* message) { SpiceMsgSurfaceDestroy* surface_destroy = (SpiceMsgSurfaceDestroy*)message->data(); - PANIC_ON(surface_destroy->surface_id != 0); - - destroy_primary_surface(); + if (surface_destroy->surface_id == 0) { //fixme + destroy_primary_surface(); + } else { + destroy_surface(surface_destroy->surface_id); + } } #define PRE_DRAW @@ -1511,102 +1666,115 @@ void DisplayChannel::handle_surface_destroy(RedPeer::InMessage* message) #define DRAW(type) { \ PRE_DRAW; \ - _canvas->draw_##type(*type, message->size()); \ + canvas->draw_##type(*type, message->size()); \ POST_DRAW; \ invalidate(type->base.box, false); \ } void DisplayChannel::handle_copy_bits(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayCopyBits* copy_bits = (SpiceMsgDisplayCopyBits*)message->data(); - PANIC_ON(copy_bits->base.surface_id != 0); PRE_DRAW; - _canvas->copy_bits(*copy_bits, message->size()); + canvas = surfaces_mngr.get_canvas(copy_bits->base.surface_id); + canvas->copy_bits(*copy_bits, message->size()); POST_DRAW; invalidate(copy_bits->base.box, false); } void DisplayChannel::handle_draw_fill(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawFill* fill = (SpiceMsgDisplayDrawFill*)message->data(); - PANIC_ON(fill->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(fill->base.surface_id); DRAW(fill); } void DisplayChannel::handle_draw_opaque(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawOpaque* opaque = (SpiceMsgDisplayDrawOpaque*)message->data(); - PANIC_ON(opaque->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(opaque->base.surface_id); DRAW(opaque); } void DisplayChannel::handle_draw_copy(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawCopy* copy = (SpiceMsgDisplayDrawCopy*)message->data(); - PANIC_ON(copy->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(copy->base.surface_id); DRAW(copy); } void DisplayChannel::handle_draw_blend(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawBlend* blend = (SpiceMsgDisplayDrawBlend*)message->data(); - PANIC_ON(blend->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(blend->base.surface_id); DRAW(blend); } void DisplayChannel::handle_draw_blackness(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawBlackness* blackness = (SpiceMsgDisplayDrawBlackness*)message->data(); - PANIC_ON(blackness->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(blackness->base.surface_id); DRAW(blackness); } void DisplayChannel::handle_draw_whiteness(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawWhiteness* whiteness = (SpiceMsgDisplayDrawWhiteness*)message->data(); - PANIC_ON(whiteness->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(whiteness->base.surface_id); DRAW(whiteness); } void DisplayChannel::handle_draw_invers(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawInvers* invers = (SpiceMsgDisplayDrawInvers*)message->data(); - PANIC_ON(invers->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(invers->base.surface_id); DRAW(invers); } void DisplayChannel::handle_draw_rop3(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawRop3* rop3 = (SpiceMsgDisplayDrawRop3*)message->data(); - PANIC_ON(rop3->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(rop3->base.surface_id); DRAW(rop3); } void DisplayChannel::handle_draw_stroke(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawStroke* stroke = (SpiceMsgDisplayDrawStroke*)message->data(); - PANIC_ON(stroke->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(stroke->base.surface_id); DRAW(stroke); } void DisplayChannel::handle_draw_text(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawText* text = (SpiceMsgDisplayDrawText*)message->data(); - PANIC_ON(text->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(text->base.surface_id); DRAW(text); } void DisplayChannel::handle_draw_transparent(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawTransparent* transparent = (SpiceMsgDisplayDrawTransparent*)message->data(); - PANIC_ON(transparent->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(transparent->base.surface_id); DRAW(transparent); } void DisplayChannel::handle_draw_alpha_blend(RedPeer::InMessage* message) { + Canvas *canvas; SpiceMsgDisplayDrawAlphaBlend* alpha_blend = (SpiceMsgDisplayDrawAlphaBlend*)message->data(); - PANIC_ON(alpha_blend->base.surface_id != 0); + canvas = surfaces_mngr.get_canvas(alpha_blend->base.surface_id); DRAW(alpha_blend); } diff --git a/client/display_channel.h b/client/display_channel.h index d603a265..b0bfbf20 100644 --- a/client/display_channel.h +++ b/client/display_channel.h @@ -79,6 +79,21 @@ private: DisplayChannel& _channel; }; +class DisplaySurfacesManger { +public: + void add_surface(int surface_id, SpiceCanvas *surface); + void del_surface(int surface_id); + void add_canvas(int surface_id, Canvas *canvas); + void del_canvas(int surface_id); + + CSurfaces& get_surfaces(); + bool is_present_canvas(int surface_id); + Canvas* get_canvas(int surface_id); +private: + CSurfaces surfaces; + CCanvases canvases; +}; + class DisplayChannel: public RedChannel, public ScreenLayer { public: DisplayChannel(RedClient& client, uint32_t id, @@ -117,22 +132,24 @@ protected: private: void set_draw_handlers(); void clear_draw_handlers(); - bool create_cairo_canvas(int width, int height, int depth); + bool create_cairo_canvas(int surface_id, int width, int height, int depth); #ifdef USE_OGL - bool create_ogl_canvas(int width, int height, int depth, bool recreate, + bool create_ogl_canvas(int surface_id, int width, int height, int depth, bool recreate, RenderType rendertype); #endif #ifdef WIN32 - bool create_gdi_canvas(int width, int height, int depth); + bool create_gdi_canvas(int surface_id, int width, int height, int depth); #endif - void destroy_canvas(); - void create_canvas(const std::vector<int>& canvas_type, int width, int height, + void destroy_canvas(int surface_id); + void create_canvas(int surface_id, const std::vector<int>& canvas_type, int width, int height, int depth); void destroy_strams(); void update_cursor(); void create_primary_surface(int width, int height, int depth); + void create_surface(int surface_id, int width, int height, int depth); void destroy_primary_surface(); + void destroy_surface(int surface_id); void handle_mode(RedPeer::InMessage* message); void handle_mark(RedPeer::InMessage* message); @@ -174,7 +191,7 @@ private: static void set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_rects, SpiceRect*& clip_rects, unsigned long addr_offset, uint8_t *min, uint8_t *max); private: - std::auto_ptr<Canvas> _canvas; + DisplaySurfacesManger surfaces_mngr; PixmapCache& _pixmap_cache; PaletteCache _palette_cache; GlzDecoderWindow& _glz_window; @@ -216,6 +233,8 @@ private: friend class SetModeEvent; friend class CreatePrimarySurfaceEvent; friend class DestroyPrimarySurfaceEvent; + friend class CreateSurfaceEvent; + friend class DestroySurfaceEvent; friend class ActivateTimerEvent; friend class VideoStream; friend class StreamsTrigger; diff --git a/client/red_cairo_canvas.cpp b/client/red_cairo_canvas.cpp index 02c105a6..71621d1d 100644 --- a/client/red_cairo_canvas.cpp +++ b/client/red_cairo_canvas.cpp @@ -25,8 +25,8 @@ #include "red_pixmap_cairo.h" CCanvas::CCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window) - : Canvas (pixmap_cache, palette_cache, glz_decoder_window) + GlzDecoderWindow &glz_decoder_window, CSurfaces& csurfaces) + : Canvas (pixmap_cache, palette_cache, glz_decoder_window, csurfaces) , _pixmap (0) { } @@ -94,6 +94,7 @@ void CCanvas::set_mode(int width, int height, int depth, RedWindow *win) if (!(_canvas = canvas_create(surface, depth, &pixmap_cache().base, &palette_cache().base, + &csurfaces().base, &glz_decoder()))) { THROW("create canvas failed"); } diff --git a/client/red_cairo_canvas.h b/client/red_cairo_canvas.h index 51c6c5ad..ce76fefc 100644 --- a/client/red_cairo_canvas.h +++ b/client/red_cairo_canvas.h @@ -26,7 +26,7 @@ class RedPixmap; class CCanvas: public Canvas { public: CCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window); + GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces); virtual ~CCanvas(); virtual void set_mode(int x, int y, int bits, RedWindow *win); diff --git a/client/red_gdi_canvas.cpp b/client/red_gdi_canvas.cpp index 9f38dfb1..bfab546c 100644 --- a/client/red_gdi_canvas.cpp +++ b/client/red_gdi_canvas.cpp @@ -24,8 +24,8 @@ #include "red_pixmap_gdi.h" GDICanvas::GDICanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window) - : Canvas (pixmap_cache, palette_cache, glz_decoder_window) + GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces) + : Canvas (pixmap_cache, palette_cache, glz_decoder_window, csurfaces) , _pixmap (0) { } @@ -38,6 +38,7 @@ GDICanvas::~GDICanvas() void GDICanvas::destroy() { if (_canvas) { + _canvas->ops->destroy(_canvas); _canvas = NULL; } destroy_pixmap(); @@ -84,6 +85,7 @@ void GDICanvas::set_mode(int width, int height, int depth) &_pixmap->get_mutex(), depth, &pixmap_cache().base, &palette_cache().base, + &csurfaces().base, &glz_decoder()))) { THROW("create canvas failed"); } diff --git a/client/red_gdi_canvas.h b/client/red_gdi_canvas.h index 83fc1205..b0a21583 100644 --- a/client/red_gdi_canvas.h +++ b/client/red_gdi_canvas.h @@ -28,7 +28,7 @@ class RedPixmap; class GDICanvas: public Canvas { public: GDICanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window); + GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces); virtual ~GDICanvas(); virtual void set_mode(int x, int y, int bits); diff --git a/client/red_gl_canvas.cpp b/client/red_gl_canvas.cpp index c6bb1137..f9c4256b 100644 --- a/client/red_gl_canvas.cpp +++ b/client/red_gl_canvas.cpp @@ -25,8 +25,8 @@ #include <GL/glx.h> GCanvas::GCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window) - : Canvas(pixmap_cache, palette_cache, glz_decoder_window) + GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces) + : Canvas(pixmap_cache, palette_cache, glz_decoder_window, csurfaces) , _pixmap (0) , _textures_lost (false) { @@ -92,6 +92,7 @@ void GCanvas::set_mode(int width, int height, int depth, RedWindow *win, if (!(_canvas = gl_canvas_create(width, height, depth, &pixmap_cache().base, &palette_cache().base, + &csurfaces().base, &glz_decoder()))) { THROW("create canvas failed"); } diff --git a/client/red_gl_canvas.h b/client/red_gl_canvas.h index 983f7729..4a9f5a90 100644 --- a/client/red_gl_canvas.h +++ b/client/red_gl_canvas.h @@ -29,7 +29,7 @@ class RedPixmapGL; class GCanvas: public Canvas { public: GCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache, - GlzDecoderWindow &glz_decoder_window); + GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces); virtual ~GCanvas(); void set_mode(int width, int height, int depth, RedWindow *win, |