diff options
-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 | ||||
-rw-r--r-- | common/cairo_canvas.c | 402 | ||||
-rw-r--r-- | common/cairo_canvas.h | 1 | ||||
-rw-r--r-- | common/canvas_base.c | 530 | ||||
-rw-r--r-- | common/canvas_base.h | 76 | ||||
-rw-r--r-- | common/gdi_canvas.c | 465 | ||||
-rw-r--r-- | common/gdi_canvas.h | 1 | ||||
-rw-r--r-- | common/gl_canvas.c | 2 | ||||
-rw-r--r-- | common/gl_canvas.h | 1 | ||||
-rw-r--r-- | server/red_dispatcher.c | 1 | ||||
-rw-r--r-- | server/red_worker.c | 749 | ||||
-rw-r--r-- | server/red_worker.h | 1 | ||||
-rw-r--r-- | server/vd_interface.h | 5 |
22 files changed, 2129 insertions, 648 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, diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c index 770ca4ff..17a40a40 100644 --- a/common/cairo_canvas.c +++ b/common/cairo_canvas.c @@ -51,11 +51,18 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas, return pixman_image_create_solid_fill(&c); } - case SPICE_BRUSH_TYPE_PATTERN: { + case SPICE_BRUSH_TYPE_PATTERN: { + CairoCanvas *surface_canvas; pixman_image_t* surface; pixman_transform_t t; - surface = canvas_get_image(&canvas->base, brush->u.pattern.pat); + surface_canvas = (CairoCanvas *)canvas_get_surface(&canvas->base, brush->u.pattern.pat); + if (surface_canvas) { + surface = surface_canvas->image; + surface = pixman_image_ref(surface); + } else { + surface = canvas_get_image(&canvas->base, brush->u.pattern.pat); + } pixman_transform_init_translate(&t, pixman_int_to_fixed(-brush->u.pattern.pos.x), pixman_int_to_fixed(-brush->u.pattern.pos.y)); @@ -70,6 +77,14 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas, } } +static pixman_image_t *get_image(SpiceCanvas *canvas) +{ + CairoCanvas *cairo_canvas = (CairoCanvas *)canvas; + + pixman_image_ref(cairo_canvas->image); + + return cairo_canvas->image; +} static void copy_region(SpiceCanvas *spice_canvas, pixman_region32_t *dest_region, @@ -194,16 +209,16 @@ static void fill_solid_rects_rop(SpiceCanvas *spice_canvas, } } -static void fill_tiled_rects(SpiceCanvas *spice_canvas, - pixman_box32_t *rects, - int n_rects, - pixman_image_t *tile, - int offset_x, int offset_y) +static void __fill_tiled_rects(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; int i; - for (i = 0; i < n_rects; i++) { + for (i = 0; i < n_rects; i++) { spice_pixman_tile_rect(canvas->image, rects[i].x1, rects[i].y1, rects[i].x2 - rects[i].x1, @@ -212,17 +227,37 @@ static void fill_tiled_rects(SpiceCanvas *spice_canvas, } } -static void fill_tiled_rects_rop(SpiceCanvas *spice_canvas, - pixman_box32_t *rects, - int n_rects, - pixman_image_t *tile, - int offset_x, int offset_y, - SpiceROP rop) +static void fill_tiled_rects(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y) +{ + __fill_tiled_rects(spice_canvas, rects, n_rects, tile, offset_x, offset_y); +} + +static void fill_tiled_rects_from_surface(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + SpiceCanvas *surface_canvas, + int offset_x, int offset_y) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __fill_tiled_rects(spice_canvas, rects, n_rects, cairo_surface_canvas->image, offset_x, + offset_y); +} + +static void __fill_tiled_rects_rop(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y, + SpiceROP rop) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; int i; - for (i = 0; i < n_rects; i++) { + for (i = 0; i < n_rects; i++) { spice_pixman_tile_rect_rop(canvas->image, rects[i].x1, rects[i].y1, rects[i].x2 - rects[i].x1, @@ -231,11 +266,32 @@ static void fill_tiled_rects_rop(SpiceCanvas *spice_canvas, rop); } } +static void fill_tiled_rects_rop(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + pixman_image_t *tile, + int offset_x, int offset_y, + SpiceROP rop) +{ + __fill_tiled_rects_rop(spice_canvas, rects, n_rects, tile, offset_x, offset_y, rop); +} -static void blit_image(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src_image, - int offset_x, int offset_y) +static void fill_tiled_rects_rop_from_surface(SpiceCanvas *spice_canvas, + pixman_box32_t *rects, + int n_rects, + SpiceCanvas *surface_canvas, + int offset_x, int offset_y, + SpiceROP rop) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __fill_tiled_rects_rop(spice_canvas, rects, n_rects, cairo_surface_canvas->image, offset_x, + offset_y, rop); +} + +static void __blit_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_box32_t *rects; @@ -262,11 +318,28 @@ static void blit_image(SpiceCanvas *spice_canvas, } } -static void blit_image_rop(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src_image, - int offset_x, int offset_y, - SpiceROP rop) +static void blit_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y) +{ + __blit_image(spice_canvas, region, src_image, offset_x, offset_y); +} + +static void blit_image_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int offset_x, int offset_y) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __blit_image(spice_canvas, region, cairo_surface_canvas->image, offset_x, offset_y); +} + +static void __blit_image_rop(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y, + SpiceROP rop) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_box32_t *rects; @@ -293,14 +366,35 @@ static void blit_image_rop(SpiceCanvas *spice_canvas, } } -static void scale_image(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src, - int src_x, int src_y, - int src_width, int src_height, - int dest_x, int dest_y, - int dest_width, int dest_height, - int scale_mode) +static void blit_image_rop(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y, + SpiceROP rop) +{ + __blit_image_rop(spice_canvas, region, src_image, offset_x, offset_y, rop); +} + +static void blit_image_rop_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int offset_x, int offset_y, + SpiceROP rop) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __blit_image_rop(spice_canvas, region, cairo_surface_canvas->image, offset_x, offset_y, rop); +} + + + +static void __scale_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; @@ -337,14 +431,41 @@ static void scale_image(SpiceCanvas *spice_canvas, pixman_image_set_clip_region32(canvas->image, NULL); } -static void scale_image_rop(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src, - int src_x, int src_y, - int src_width, int src_height, - int dest_x, int dest_y, - int dest_width, int dest_height, - int scale_mode, SpiceROP rop) +static void scale_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode) +{ + __scale_image(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x, dest_y, + dest_width,dest_height,scale_mode); +} + +static void scale_image_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __scale_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, src_width, + src_height, dest_x, dest_y, dest_width,dest_height,scale_mode); +} + +static void __scale_image_rop(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, SpiceROP rop) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; @@ -407,13 +528,40 @@ static void scale_image_rop(SpiceCanvas *spice_canvas, pixman_image_unref(scaled); } -static void blend_image(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src, - int src_x, int src_y, - int dest_x, int dest_y, - int width, int height, - int overall_alpha) +static void scale_image_rop(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, SpiceROP rop) +{ + __scale_image_rop(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x, + dest_y, dest_width, dest_height, scale_mode, rop); +} + +static void scale_image_rop_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, SpiceROP rop) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __scale_image_rop(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, src_width, + src_height, dest_x, dest_y, dest_width, dest_height, scale_mode, rop); +} + +static void __blend_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int overall_alpha) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_image_t *mask; @@ -444,15 +592,40 @@ static void blend_image(SpiceCanvas *spice_canvas, pixman_image_set_clip_region32(canvas->image, NULL); } -static void blend_scale_image(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src, - int src_x, int src_y, - int src_width, int src_height, - int dest_x, int dest_y, - int dest_width, int dest_height, - int scale_mode, - int overall_alpha) +static void blend_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int overall_alpha) +{ + __blend_image(spice_canvas, region, src, src_x, src_y, dest_x, dest_y, width, height, + overall_alpha); +} + +static void blend_image_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int overall_alpha) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __blend_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, dest_x, dest_y, + width, height, overall_alpha); +} + +static void __blend_scale_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, + int overall_alpha) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; @@ -501,11 +674,41 @@ static void blend_scale_image(SpiceCanvas *spice_canvas, pixman_image_set_clip_region32(canvas->image, NULL); } -static void colorkey_image(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src_image, - int offset_x, int offset_y, - uint32_t transparent_color) +static void blend_scale_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, + int overall_alpha) +{ + __blend_scale_image(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x, + dest_y, dest_width, dest_height, scale_mode, overall_alpha); +} + +static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, + int overall_alpha) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __blend_scale_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, src_width, + src_height, dest_x, dest_y, dest_width, dest_height, scale_mode, + overall_alpha); +} + +static void __colorkey_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y, + uint32_t transparent_color) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_box32_t *rects; @@ -533,14 +736,34 @@ static void colorkey_image(SpiceCanvas *spice_canvas, } } -static void colorkey_scale_image(SpiceCanvas *spice_canvas, - pixman_region32_t *region, - pixman_image_t *src, - int src_x, int src_y, - int src_width, int src_height, - int dest_x, int dest_y, - int dest_width, int dest_height, - uint32_t transparent_color) +static void colorkey_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src_image, + int offset_x, int offset_y, + uint32_t transparent_color) +{ + __colorkey_image(spice_canvas, region, src_image, offset_x, offset_y, transparent_color); +} + +static void colorkey_image_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int offset_x, int offset_y, + uint32_t transparent_color) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __colorkey_image(spice_canvas, region, cairo_surface_canvas->image, offset_x, offset_y, + transparent_color); +} + +static void __colorkey_scale_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + uint32_t transparent_color) { CairoCanvas *canvas = (CairoCanvas *)spice_canvas; pixman_transform_t transform; @@ -600,6 +823,34 @@ static void colorkey_scale_image(SpiceCanvas *spice_canvas, pixman_image_unref(scaled); } +static void colorkey_scale_image(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + pixman_image_t *src, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + uint32_t transparent_color) +{ + __colorkey_scale_image(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x, + dest_y, dest_width, dest_height, transparent_color); +} + +static void colorkey_scale_image_from_surface(SpiceCanvas *spice_canvas, + pixman_region32_t *region, + SpiceCanvas *surface_canvas, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + uint32_t transparent_color) +{ + CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas; + __colorkey_scale_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, + src_width, src_height, dest_x, dest_y, dest_width, dest_height, + transparent_color); +} + static void canvas_put_image(SpiceCanvas *spice_canvas, #ifdef WIN32 HDC dc, @@ -803,6 +1054,7 @@ SpiceCanvas *canvas_create(pixman_image_t *image, int bits #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , SpiceImageCache *bits_cache #endif + , SpiceImageSurfaces *surfaces , SpiceGlzDecoder *glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , SpiceVirtMapping *virt_mapping @@ -826,6 +1078,7 @@ SpiceCanvas *canvas_create(pixman_image_t *image, int bits #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , bits_cache #endif + , surfaces , glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , virt_mapping @@ -858,15 +1111,26 @@ void cairo_canvas_init() //unsafe global function cairo_canvas_ops.fill_solid_rects = fill_solid_rects; cairo_canvas_ops.fill_solid_rects_rop = fill_solid_rects_rop; cairo_canvas_ops.fill_tiled_rects = fill_tiled_rects; + cairo_canvas_ops.fill_tiled_rects_from_surface = fill_tiled_rects_from_surface; cairo_canvas_ops.fill_tiled_rects_rop = fill_tiled_rects_rop; + cairo_canvas_ops.fill_tiled_rects_rop_from_surface = fill_tiled_rects_rop_from_surface; cairo_canvas_ops.blit_image = blit_image; + cairo_canvas_ops.blit_image_from_surface = blit_image_from_surface; cairo_canvas_ops.blit_image_rop = blit_image_rop; + cairo_canvas_ops.blit_image_rop_from_surface = blit_image_rop_from_surface; cairo_canvas_ops.scale_image = scale_image; + cairo_canvas_ops.scale_image_from_surface = scale_image_from_surface; cairo_canvas_ops.scale_image_rop = scale_image_rop; + cairo_canvas_ops.scale_image_rop_from_surface = scale_image_rop_from_surface; cairo_canvas_ops.blend_image = blend_image; + cairo_canvas_ops.blend_image_from_surface = blend_image_from_surface; cairo_canvas_ops.blend_scale_image = blend_scale_image; + cairo_canvas_ops.blend_scale_image_from_surface = blend_scale_image_from_surface; cairo_canvas_ops.colorkey_image = colorkey_image; + cairo_canvas_ops.colorkey_image_from_surface = colorkey_image_from_surface; cairo_canvas_ops.colorkey_scale_image = colorkey_scale_image; + cairo_canvas_ops.colorkey_scale_image_from_surface = colorkey_scale_image_from_surface; cairo_canvas_ops.copy_region = copy_region; + cairo_canvas_ops.get_image = get_image; rop3_init(); } diff --git a/common/cairo_canvas.h b/common/cairo_canvas.h index 3f6fbbc6..e65b4076 100644 --- a/common/cairo_canvas.h +++ b/common/cairo_canvas.h @@ -33,6 +33,7 @@ SpiceCanvas *canvas_create(pixman_image_t *image, int bits #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , SpiceImageCache *bits_cache #endif + , SpiceImageSurfaces *surfaces , SpiceGlzDecoder *glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , SpiceVirtMapping *virt_mapping diff --git a/common/canvas_base.c b/common/canvas_base.c index e13a005b..e15a971a 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -190,6 +190,8 @@ typedef struct CanvasBase { HDC dc; #endif + SpiceImageSurfaces *surfaces; + LzData lz_data; GlzData glz_data; @@ -948,6 +950,34 @@ static void dump_surface(pixman_image_t *surface, int cache) #endif +static SpiceCanvas *canvas_get_surface_internal(CanvasBase *canvas, SPICE_ADDRESS addr) +{ + SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr); + access_test(canvas, descriptor, sizeof(SpiceImageDescriptor)); + + if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) { + SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor; + access_test(canvas, descriptor, sizeof(SpiceSurfaceImage)); + return canvas->surfaces->ops->get(canvas->surfaces, surface->surface.surface_id); + } + return NULL; +} + +static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_ADDRESS addr) +{ + SpiceImageDescriptor *descriptor; + + descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr); + access_test(canvas, descriptor, sizeof(SpiceImageDescriptor)); + + if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) { + SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor; + access_test(canvas, descriptor, sizeof(SpiceSurfaceImage)); + return canvas->surfaces->ops->get(canvas->surfaces, surface->surface.surface_id); + } + return NULL; +} + #if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE) //#define DEBUG_LZ @@ -1065,6 +1095,16 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE #endif +static SpiceCanvas *canvas_get_surface_mask(CanvasBase *canvas, SPICE_ADDRESS addr) +{ + return canvas_get_surface_mask_internal(canvas, addr); +} + +static SpiceCanvas *canvas_get_surface(CanvasBase *canvas, SPICE_ADDRESS addr) +{ + return canvas_get_surface_internal(canvas, addr); +} + static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr) { return canvas_get_image_internal(canvas, addr, TRUE); @@ -1318,10 +1358,6 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int *needs_invert_out = 0; } - if (!mask->bitmap) { - return NULL; - } - descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(mask->bitmap); access_test(canvas, descriptor, sizeof(SpiceImageDescriptor)); need_invers = mask->flags & SPICE_MASK_FLAGS_INVERS; @@ -1807,6 +1843,7 @@ static void canvas_mask_pixman(CanvasBase *canvas, pixman_region32_t *dest_region, SpiceQMask *mask, int x, int y) { + SpiceCanvas *surface_canvas; pixman_image_t *image, *subimage; int needs_invert; pixman_region32_t mask_region; @@ -1815,13 +1852,19 @@ static void canvas_mask_pixman(CanvasBase *canvas, int mask_width, mask_height, mask_stride; pixman_box32_t extents; - needs_invert = FALSE; - image = canvas_get_mask(canvas, - mask, - &needs_invert); + if (!mask->bitmap) { + return; + } - if (image == NULL) { - return; /* no mask */ + surface_canvas = canvas_get_surface_mask(canvas, mask->bitmap); + if (surface_canvas) { + needs_invert = mask->flags & SPICE_MASK_FLAGS_INVERS; + image = surface_canvas->ops->get_image(surface_canvas); + } else { + needs_invert = FALSE; + image = canvas_get_mask(canvas, + mask, + &needs_invert); } mask_data = pixman_image_get_data(image); @@ -1921,20 +1964,35 @@ static void draw_brush(SpiceCanvas *canvas, canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, color, rop); } break; - case SPICE_BRUSH_TYPE_PATTERN: + case SPICE_BRUSH_TYPE_PATTERN: { + SpiceCanvas *surface_canvas; + pattern = &brush->u.pattern; - tile = canvas_get_image(canvas_base, pattern->pat); offset_x = pattern->pos.x; offset_y = pattern->pos.y; - if (rop == SPICE_ROP_COPY) { - canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y); + surface_canvas = canvas_get_surface(canvas_base, pattern->pat); + if (surface_canvas) { + if (rop == SPICE_ROP_COPY) { + canvas->ops->fill_tiled_rects_from_surface(canvas, rects, n_rects, surface_canvas, + offset_x, offset_y); + } else { + canvas->ops->fill_tiled_rects_rop_from_surface(canvas, rects, n_rects, + surface_canvas, offset_x, offset_y, + rop); + } } else { - canvas->ops->fill_tiled_rects_rop(canvas, rects, n_rects, - tile, offset_x, offset_y, rop); + tile = canvas_get_image(canvas_base, pattern->pat); + if (rop == SPICE_ROP_COPY) { + canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y); + } else { + canvas->ops->fill_tiled_rects_rop(canvas, rects, n_rects, + tile, offset_x, offset_y, rop); + } + pixman_image_unref(tile); } - pixman_image_unref(tile); break; + } case SPICE_BRUSH_TYPE_NONE: /* Still need to do *something* here, because rop could be e.g invert dest */ canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, 0, rop); @@ -1991,6 +2049,7 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl { CanvasBase *canvas = (CanvasBase *)spice_canvas; pixman_region32_t dest_region; + SpiceCanvas *surface_canvas; pixman_image_t *src_image; SpiceROP rop; @@ -2013,36 +2072,67 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl return; } - src_image = canvas_get_image(canvas, copy->src_bitmap); - - if (rect_is_same_size(bbox, ©->src_area)) { - if (rop == SPICE_ROP_COPY) { - spice_canvas->ops->blit_image(spice_canvas, &dest_region, - src_image, - bbox->left - copy->src_area.left, - bbox->top - copy->src_area.top); + surface_canvas = canvas_get_surface(canvas, copy->src_bitmap); + if (surface_canvas) { + if (rect_is_same_size(bbox, ©->src_area)) { + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->blit_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + bbox->left - copy->src_area.left, + bbox->top - copy->src_area.top); + } else { + spice_canvas->ops->blit_image_rop_from_surface(spice_canvas, &dest_region, + surface_canvas, + bbox->left - copy->src_area.left, + bbox->top - copy->src_area.top, + rop); + } } else { - spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region, - src_image, - bbox->left - copy->src_area.left, - bbox->top - copy->src_area.top, - rop); + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->scale_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + copy->src_area.left, + copy->src_area.top, + copy->src_area.right - copy->src_area.left, + copy->src_area.bottom - copy->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + copy->scale_mode); + } else { + spice_canvas->ops->scale_image_rop_from_surface(spice_canvas, &dest_region, + surface_canvas, + copy->src_area.left, + copy->src_area.top, + copy->src_area.right - copy->src_area.left, + copy->src_area.bottom - copy->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + copy->scale_mode, + rop); + } } } else { - if (rop == SPICE_ROP_COPY) { - spice_canvas->ops->scale_image(spice_canvas, &dest_region, - src_image, - copy->src_area.left, - copy->src_area.top, - copy->src_area.right - copy->src_area.left, - copy->src_area.bottom - copy->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - copy->scale_mode); + src_image = canvas_get_image(canvas, copy->src_bitmap); + if (rect_is_same_size(bbox, ©->src_area)) { + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->blit_image(spice_canvas, &dest_region, + src_image, + bbox->left - copy->src_area.left, + bbox->top - copy->src_area.top); + } else { + spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region, + src_image, + bbox->left - copy->src_area.left, + bbox->top - copy->src_area.top, + rop); + } } else { - spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region, + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->scale_image(spice_canvas, &dest_region, src_image, copy->src_area.left, copy->src_area.top, @@ -2052,18 +2142,31 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl bbox->top, bbox->right - bbox->left, bbox->bottom - bbox->top, - copy->scale_mode, - rop); + copy->scale_mode); + } else { + spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region, + src_image, + copy->src_area.left, + copy->src_area.top, + copy->src_area.right - copy->src_area.left, + copy->src_area.bottom - copy->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + copy->scale_mode, + rop); + } } + pixman_image_unref(src_image); } - - pixman_image_unref(src_image); pixman_region32_fini(&dest_region); } static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent) { CanvasBase *canvas = (CanvasBase *)spice_canvas; + SpiceCanvas *surface_canvas; pixman_image_t *src_image; pixman_region32_t dest_region; @@ -2080,29 +2183,50 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, return; } - src_image = canvas_get_image(canvas, transparent->src_bitmap); - - if (rect_is_same_size(bbox, &transparent->src_area)) { - spice_canvas->ops->colorkey_image(spice_canvas, &dest_region, - src_image, - bbox->left - transparent->src_area.left, - bbox->top - transparent->src_area.top, - transparent->true_color); + surface_canvas = canvas_get_surface(canvas, transparent->src_bitmap); + if (surface_canvas) { + if (rect_is_same_size(bbox, &transparent->src_area)) { + spice_canvas->ops->colorkey_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + bbox->left - transparent->src_area.left, + bbox->top - transparent->src_area.top, + transparent->true_color); + } else { + spice_canvas->ops->colorkey_scale_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + transparent->src_area.left, + transparent->src_area.top, + transparent->src_area.right - transparent->src_area.left, + transparent->src_area.bottom - transparent->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + transparent->true_color); + } } else { - spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region, - src_image, - transparent->src_area.left, - transparent->src_area.top, - transparent->src_area.right - transparent->src_area.left, - transparent->src_area.bottom - transparent->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - transparent->true_color); + src_image = canvas_get_image(canvas, transparent->src_bitmap); + if (rect_is_same_size(bbox, &transparent->src_area)) { + spice_canvas->ops->colorkey_image(spice_canvas, &dest_region, + src_image, + bbox->left - transparent->src_area.left, + bbox->top - transparent->src_area.top, + transparent->true_color); + } else { + spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region, + src_image, + transparent->src_area.left, + transparent->src_area.top, + transparent->src_area.right - transparent->src_area.left, + transparent->src_area.bottom - transparent->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + transparent->true_color); + } + pixman_image_unref(src_image); } - - pixman_image_unref(src_image); pixman_region32_fini(&dest_region); } @@ -2110,6 +2234,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, { CanvasBase *canvas = (CanvasBase *)spice_canvas; pixman_region32_t dest_region; + SpiceCanvas *surface_canvas; pixman_image_t *src_image; pixman_region32_init_rect(&dest_region, @@ -2126,34 +2251,62 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, return; } - src_image = canvas_get_image(canvas, alpha_blend->src_bitmap); - - if (rect_is_same_size(bbox, &alpha_blend->src_area)) { - spice_canvas->ops->blend_image(spice_canvas, &dest_region, - src_image, - alpha_blend->src_area.left, - alpha_blend->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - alpha_blend->alpha); - } else { - spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region, - src_image, - alpha_blend->src_area.left, - alpha_blend->src_area.top, - alpha_blend->src_area.right - alpha_blend->src_area.left, - alpha_blend->src_area.bottom - alpha_blend->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - SPICE_IMAGE_SCALE_MODE_NEAREST, - alpha_blend->alpha); + surface_canvas = canvas_get_surface(canvas, alpha_blend->src_bitmap); + if (surface_canvas) { + if (rect_is_same_size(bbox, &alpha_blend->src_area)) { + spice_canvas->ops->blend_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + alpha_blend->alpha); + } else { + spice_canvas->ops->blend_scale_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + alpha_blend->src_area.right - alpha_blend->src_area.left, + alpha_blend->src_area.bottom - alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + SPICE_IMAGE_SCALE_MODE_NEAREST, + alpha_blend->alpha); + } + } else { + src_image = canvas_get_image(canvas, alpha_blend->src_bitmap); + if (rect_is_same_size(bbox, &alpha_blend->src_area)) { + spice_canvas->ops->blend_image(spice_canvas, &dest_region, + src_image, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + alpha_blend->alpha); + } else { + spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region, + src_image, + alpha_blend->src_area.left, + alpha_blend->src_area.top, + alpha_blend->src_area.right - alpha_blend->src_area.left, + alpha_blend->src_area.bottom - alpha_blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + SPICE_IMAGE_SCALE_MODE_NEAREST, + alpha_blend->alpha); + } + + pixman_image_unref(src_image); } - pixman_image_unref(src_image); pixman_region32_fini(&dest_region); } @@ -2214,6 +2367,7 @@ static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spice static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend) { CanvasBase *canvas = (CanvasBase *)spice_canvas; + SpiceCanvas *surface_canvas; pixman_image_t *src_image; pixman_region32_t dest_region; SpiceROP rop; @@ -2237,40 +2391,74 @@ static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceC return; } - src_image = canvas_get_image(canvas, blend->src_bitmap); - - if (rect_is_same_size(bbox, &blend->src_area)) { - if (rop == SPICE_ROP_COPY) - spice_canvas->ops->blit_image(spice_canvas, &dest_region, - src_image, - bbox->left - blend->src_area.left, - bbox->top - blend->src_area.top); - else - spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region, + surface_canvas = canvas_get_surface(canvas, blend->src_bitmap); + if (surface_canvas) { + if (rect_is_same_size(bbox, &blend->src_area)) { + if (rop == SPICE_ROP_COPY) + spice_canvas->ops->blit_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + bbox->left - blend->src_area.left, + bbox->top - blend->src_area.top); + else + spice_canvas->ops->blit_image_rop_from_surface(spice_canvas, &dest_region, + surface_canvas, + bbox->left - blend->src_area.left, + bbox->top - blend->src_area.top, + rop); + } else { + double sx, sy; + + sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left); + sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top); + + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->scale_image_from_surface(spice_canvas, &dest_region, + surface_canvas, + blend->src_area.left, + blend->src_area.top, + blend->src_area.right - blend->src_area.left, + blend->src_area.bottom - blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + blend->scale_mode); + } else { + spice_canvas->ops->scale_image_rop_from_surface(spice_canvas, &dest_region, + surface_canvas, + blend->src_area.left, + blend->src_area.top, + blend->src_area.right - blend->src_area.left, + blend->src_area.bottom - blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + blend->scale_mode, rop); + } + } + } else { + src_image = canvas_get_image(canvas, blend->src_bitmap); + if (rect_is_same_size(bbox, &blend->src_area)) { + if (rop == SPICE_ROP_COPY) + spice_canvas->ops->blit_image(spice_canvas, &dest_region, src_image, bbox->left - blend->src_area.left, - bbox->top - blend->src_area.top, - rop); - } else { - double sx, sy; - - sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left); - sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top); - - if (rop == SPICE_ROP_COPY) { - spice_canvas->ops->scale_image(spice_canvas, &dest_region, - src_image, - blend->src_area.left, - blend->src_area.top, - blend->src_area.right - blend->src_area.left, - blend->src_area.bottom - blend->src_area.top, - bbox->left, - bbox->top, - bbox->right - bbox->left, - bbox->bottom - bbox->top, - blend->scale_mode); + bbox->top - blend->src_area.top); + else + spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region, + src_image, + bbox->left - blend->src_area.left, + bbox->top - blend->src_area.top, + rop); } else { - spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region, + double sx, sy; + + sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left); + sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top); + + if (rop == SPICE_ROP_COPY) { + spice_canvas->ops->scale_image(spice_canvas, &dest_region, src_image, blend->src_area.left, blend->src_area.top, @@ -2280,11 +2468,23 @@ static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceC bbox->top, bbox->right - bbox->left, bbox->bottom - bbox->top, - blend->scale_mode, rop); + blend->scale_mode); + } else { + spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region, + src_image, + blend->src_area.left, + blend->src_area.top, + blend->src_area.right - blend->src_area.left, + blend->src_area.bottom - blend->src_area.top, + bbox->left, + bbox->top, + bbox->right - bbox->left, + bbox->bottom - bbox->top, + blend->scale_mode, rop); + } } + pixman_image_unref(src_image); } - - pixman_image_unref(src_image); pixman_region32_fini(&dest_region); } @@ -2382,7 +2582,11 @@ typedef struct { SpiceROP back_rop; int solid; uint32_t color; - pixman_image_t *tile; + int use_surface_canvas; + union { + SpiceCanvas *surface_canvas; + pixman_image_t *tile; + }; int tile_offset_x; int tile_offset_y; } StrokeGC; @@ -2505,16 +2709,31 @@ static void stroke_fill_rects(lineGC * pGC, } } else { if (rop == SPICE_ROP_COPY) { - canvas->ops->fill_tiled_rects(canvas, area_rects, n_area_rects, - strokeGC->tile, - strokeGC->tile_offset_x, - strokeGC->tile_offset_y); - } else { - canvas->ops->fill_tiled_rects_rop(canvas, area_rects, n_area_rects, + if (strokeGC->use_surface_canvas) { + canvas->ops->fill_tiled_rects_from_surface(canvas, area_rects, n_area_rects, + strokeGC->surface_canvas, + strokeGC->tile_offset_x, + strokeGC->tile_offset_y); + } else { + canvas->ops->fill_tiled_rects(canvas, area_rects, n_area_rects, strokeGC->tile, strokeGC->tile_offset_x, - strokeGC->tile_offset_y, - rop); + strokeGC->tile_offset_y); + } + } else { + if (strokeGC->use_surface_canvas) { + canvas->ops->fill_tiled_rects_rop_from_surface(canvas, area_rects, n_area_rects, + strokeGC->surface_canvas, + strokeGC->tile_offset_x, + strokeGC->tile_offset_y, + rop); + } else { + canvas->ops->fill_tiled_rects_rop(canvas, area_rects, n_area_rects, + strokeGC->tile, + strokeGC->tile_offset_x, + strokeGC->tile_offset_y, + rop); + } } } @@ -2661,6 +2880,7 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke) { CanvasBase *canvas = (CanvasBase *)spice_canvas; + SpiceCanvas *surface_canvas = NULL; StrokeGC gc = { { 0 } }; lineGCOps ops = { stroke_fill_spans, @@ -2754,8 +2974,16 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, break; case SPICE_BRUSH_TYPE_PATTERN: gc.solid = FALSE; - gc.tile = canvas_get_image(canvas, - stroke->brush.u.pattern.pat); + surface_canvas = canvas_get_surface(canvas, + stroke->brush.u.pattern.pat); + if (surface_canvas) { + gc.use_surface_canvas = TRUE; + gc.surface_canvas = surface_canvas; + } else { + gc.use_surface_canvas = FALSE; + gc.tile = canvas_get_image(canvas, + stroke->brush.u.pattern.pat); + } gc.tile_offset_x = stroke->brush.u.pattern.pos.x; gc.tile_offset_y = stroke->brush.u.pattern.pos.y; break; @@ -2817,17 +3045,20 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, } stroke_lines_free(&lines); - if (!gc.solid && gc.tile) { + if (!gc.solid && gc.tile && !surface_canvas) { pixman_image_unref(gc.tile); } pixman_region32_fini(&gc.dest_region); } + +//need surfaces handling here !!! static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3) { CanvasBase *canvas = (CanvasBase *)spice_canvas; + SpiceCanvas *surface_canvas; pixman_region32_t dest_region; pixman_image_t *d; pixman_image_t *s; @@ -2848,7 +3079,12 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, heigth = bbox->bottom - bbox->top; d = canvas_get_image_from_self(spice_canvas, bbox->left, bbox->top, width, heigth); - s = canvas_get_image(canvas, rop3->src_bitmap); + surface_canvas = canvas_get_surface(canvas, rop3->src_bitmap); + if (surface_canvas) { + s = surface_canvas->ops->get_image(surface_canvas); + } else { + s = canvas_get_image(canvas, rop3->src_bitmap); + } if (!rect_is_same_size(bbox, &rop3->src_area)) { pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth, @@ -2866,7 +3102,15 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, CANVAS_ERROR("bad src bitmap size"); } if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) { - pixman_image_t *p = canvas_get_image(canvas, rop3->brush.u.pattern.pat); + SpiceCanvas *_surface_canvas; + pixman_image_t *p; + + _surface_canvas = canvas_get_surface(canvas, rop3->brush.u.pattern.pat); + if (_surface_canvas) { + p = _surface_canvas->ops->get_image(_surface_canvas); + } else { + p = canvas_get_image(canvas, rop3->brush.u.pattern.pat); + } SpicePoint pat_pos; pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p); @@ -2988,6 +3232,7 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops, #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , SpiceImageCache *bits_cache #endif + , SpiceImageSurfaces *surfaces , SpiceGlzDecoder *glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , SpiceVirtMapping *virt_mapping @@ -3020,6 +3265,7 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops, return 0; } #endif + canvas->surfaces = surfaces; canvas->glz_data.decoder = glz_decoder; if (depth == 16) { diff --git a/common/canvas_base.h b/common/canvas_base.h index bed1e1ba..0a663bd1 100644 --- a/common/canvas_base.h +++ b/common/canvas_base.h @@ -28,6 +28,7 @@ typedef void (*spice_destroy_fn_t)(void *data); typedef struct _SpiceImageCache SpiceImageCache; +typedef struct _SpiceImageSurfaces SpiceImageSurfaces; typedef struct _SpicePaletteCache SpicePaletteCache; typedef struct _SpiceGlzDecoder SpiceGlzDecoder; typedef struct _SpiceVirtMapping SpiceVirtMapping; @@ -46,6 +47,15 @@ struct _SpiceImageCache { }; typedef struct { + SpiceCanvas *(*get)(SpiceImageSurfaces *surfaces, + uint32_t surface_id); +} SpiceImageSurfacesOps; + +struct _SpiceImageSurfaces { + SpiceImageSurfacesOps *ops; +}; + +typedef struct { void (*put)(SpicePaletteCache *cache, SpicePalette *palette); SpicePalette *(*get)(SpicePaletteCache *cache, @@ -127,21 +137,41 @@ typedef struct { int n_rects, pixman_image_t *tile, int offset_x, int offset_y); + void (*fill_tiled_rects_from_surface)(SpiceCanvas *canvas, + pixman_box32_t *rects, + int n_rects, + SpiceCanvas *tile, + int offset_x, int offset_y); void (*fill_tiled_rects_rop)(SpiceCanvas *canvas, pixman_box32_t *rects, int n_rects, pixman_image_t *tile, int offset_x, int offset_y, SpiceROP rop); + void (*fill_tiled_rects_rop_from_surface)(SpiceCanvas *canvas, + pixman_box32_t *rects, + int n_rects, + SpiceCanvas *tile, + int offset_x, int offset_y, + SpiceROP rop); void (*blit_image)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, int offset_x, int offset_y); + void (*blit_image_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int offset_x, int offset_y); void (*blit_image_rop)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, int offset_x, int offset_y, SpiceROP rop); + void (*blit_image_rop_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int offset_x, int offset_y, + SpiceROP rop); void (*scale_image)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, @@ -150,6 +180,14 @@ typedef struct { int dest_x, int dest_y, int dest_width, int dest_height, int scale_mode); + void (*scale_image_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode); void (*scale_image_rop)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, @@ -158,6 +196,14 @@ typedef struct { int dest_x, int dest_y, int dest_width, int dest_height, int scale_mode, SpiceROP rop); + void (*scale_image_rop_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, SpiceROP rop); void (*blend_image)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, @@ -165,6 +211,13 @@ typedef struct { int dest_x, int dest_y, int width, int height, int overall_alpha); + void (*blend_image_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int overall_alpha); void (*blend_scale_image)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, @@ -174,11 +227,25 @@ typedef struct { int dest_width, int dest_height, int scale_mode, int overall_alpha); + void (*blend_scale_image_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + int scale_mode, + int overall_alpha); void (*colorkey_image)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, int offset_x, int offset_y, uint32_t transparent_color); + void (*colorkey_image_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int offset_x, int offset_y, + uint32_t transparent_color); void (*colorkey_scale_image)(SpiceCanvas *canvas, pixman_region32_t *region, pixman_image_t *src_image, @@ -187,9 +254,18 @@ typedef struct { int dest_x, int dest_y, int dest_width, int dest_height, uint32_t transparent_color); + void (*colorkey_scale_image_from_surface)(SpiceCanvas *canvas, + pixman_region32_t *region, + SpiceCanvas *src_image, + int src_x, int src_y, + int src_width, int src_height, + int dest_x, int dest_y, + int dest_width, int dest_height, + uint32_t transparent_color); void (*copy_region)(SpiceCanvas *canvas, pixman_region32_t *dest_region, int dx, int dy); + pixman_image_t *(*get_image)(SpiceCanvas *canvas); } SpiceCanvasOps; void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn); diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c index 5eb31fe7..75dff69a 100644 --- a/common/gdi_canvas.c +++ b/common/gdi_canvas.c @@ -42,6 +42,7 @@ struct BitmapData { uint8_t flags; HDC dc; int cache; + int from_surface; }; #define _rop3_brush 0xf0 @@ -644,7 +645,8 @@ static HBRUSH get_brush(GdiCanvas *canvas, SpiceBrush *brush) CANVAS_ERROR("CreateSolidBrush failed"); } return hbrush; - case SPICE_BRUSH_TYPE_PATTERN: { + case SPICE_BRUSH_TYPE_PATTERN: { + GdiCanvas *gdi_surface = NULL; GdiImage image; HBRUSH hbrush; pixman_image_t *surface; @@ -652,21 +654,31 @@ static HBRUSH get_brush(GdiCanvas *canvas, SpiceBrush *brush) HBITMAP bitmap; HBITMAP prev_bitmap; - surface = canvas_get_image(&canvas->base, brush->u.pattern.pat); - surface_to_image(surface, &image); - - if (!create_bitmap(&bitmap, &prev_bitmap, &dc, image.pixels, image.width, - image.height, image.stride, 32, 0)) { - CANVAS_ERROR("create_bitmap failed"); - return NULL; + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, brush->u.pattern.pat); + if (gdi_surface) { + bitmap = (HBITMAP)GetCurrentObject(gdi_surface->dc, OBJ_BITMAP); + if (!bitmap) { + CANVAS_ERROR("GetCurrentObject failed"); + } + } else { + surface = canvas_get_image(&canvas->base, brush->u.pattern.pat); + surface_to_image(surface, &image); + + if (!create_bitmap(&bitmap, &prev_bitmap, &dc, image.pixels, image.width, + image.height, image.stride, 32, 0)) { + CANVAS_ERROR("create_bitmap failed"); + return NULL; + } } if (!(hbrush = CreatePatternBrush(bitmap))) { CANVAS_ERROR("CreatePatternBrush failed"); } - release_bitmap(dc, bitmap, prev_bitmap, 0); - pixman_image_unref(surface); + if (!gdi_surface) { + release_bitmap(dc, bitmap, prev_bitmap, 0); + pixman_image_unref(surface); + } return hbrush; } case SPICE_BRUSH_TYPE_NONE: @@ -781,30 +793,53 @@ uint8_t calc_rop3_src_brush(uint16_t rop3_bits) static struct BitmapData get_mask_bitmap(struct GdiCanvas *canvas, struct SpiceQMask *mask) { + GdiCanvas *gdi_surface; pixman_image_t *surface; struct BitmapData bitmap; PixmanData *pixman_data; bitmap.hbitmap = NULL; - if (!(surface = canvas_get_mask(&canvas->base, mask, NULL))) { + if (!mask->bitmap) { return bitmap; } - pixman_data = (PixmanData *)pixman_image_get_destroy_data (surface); - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - bitmap.dc = create_compatible_dc(); - bitmap.prev_hbitmap = (HBITMAP)SelectObject(bitmap.dc, pixman_data->bitmap); - bitmap.hbitmap = pixman_data->bitmap; - ReleaseMutex(pixman_data->mutex); - bitmap.cache = 1; - } else if (!create_bitmap(&bitmap.hbitmap, &bitmap.prev_hbitmap, &bitmap.dc, - (uint8_t *)pixman_image_get_data(surface), - pixman_image_get_width(surface), - pixman_image_get_height(surface), - pixman_image_get_stride(surface), 1, 0)) { - bitmap.hbitmap = NULL; + gdi_surface = (GdiCanvas *)canvas_get_surface_mask(&canvas->base, mask->bitmap); + if (gdi_surface) { + HBITMAP _bitmap; + + _bitmap = (HBITMAP)GetCurrentObject(gdi_surface->dc, OBJ_BITMAP); + if (!_bitmap) { + CANVAS_ERROR ("GetCurrentObject failed"); + } + bitmap.dc = gdi_surface->dc; + bitmap.hbitmap = _bitmap; + bitmap.prev_hbitmap = (HBITMAP)0; + bitmap.cache = 0; + bitmap.from_surface = 1; } else { - bitmap.cache = 0; + + if (!(surface = canvas_get_mask(&canvas->base, mask, NULL))) { + return bitmap; + } + + pixman_data = (PixmanData *)pixman_image_get_destroy_data (surface); + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + bitmap.dc = create_compatible_dc(); + bitmap.prev_hbitmap = (HBITMAP)SelectObject(bitmap.dc, pixman_data->bitmap); + bitmap.hbitmap = pixman_data->bitmap; + ReleaseMutex(pixman_data->mutex); + bitmap.cache = 1; + } else if (!create_bitmap(&bitmap.hbitmap, &bitmap.prev_hbitmap, &bitmap.dc, + (uint8_t *)pixman_image_get_data(surface), + pixman_image_get_width(surface), + pixman_image_get_height(surface), + pixman_image_get_stride(surface), 1, 0)) { + bitmap.hbitmap = NULL; + } else { + bitmap.cache = 0; + } + + bitmap.from_surface = 0; } bitmap.flags = mask->flags; @@ -859,7 +894,9 @@ static void gdi_draw_bitmap_redrop(HDC dest_dc, const SpiceRect *src, const Spic static void free_mask(struct BitmapData *bitmap) { if (bitmap->hbitmap) { - release_bitmap(bitmap->dc, bitmap->hbitmap, bitmap->prev_hbitmap, bitmap->cache); + if (!bitmap->from_surface) { + release_bitmap(bitmap->dc, bitmap->hbitmap, bitmap->prev_hbitmap, bitmap->cache); + } } } @@ -985,13 +1022,15 @@ static void gdi_canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi HBRUSH brush; struct BitmapData bitmapmask; + Lock lock(*canvas->lock); + if (!(brush = get_brush(canvas, &fill->brush))) { CANVAS_ERROR("no braash"); return; } + bitmapmask = get_mask_bitmap(canvas, &fill->mask); - Lock lock(*canvas->lock); set_clip(canvas, clip); prev_hbrush = set_brush(canvas->dc, brush, &fill->brush); gdi_draw_bitmap_redrop(canvas->dc, bbox, bbox, canvas->dc, &bitmapmask, @@ -1004,40 +1043,51 @@ static void gdi_canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi static void gdi_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy) { GdiCanvas *canvas = (GdiCanvas *)spice_canvas; + GdiCanvas *gdi_surface; pixman_image_t *surface; GdiImage image; struct BitmapData bitmapmask; PixmanData *pixman_data; - bitmapmask = get_mask_bitmap(canvas, ©->mask); - surface = canvas_get_image(&canvas->base, copy->src_bitmap); - pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); - - Lock lock(*canvas->lock); - set_scale_mode(canvas, copy->scale_mode); - set_clip(canvas, clip); - - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - HDC dc; - HBITMAP prev_bitmap; - - dc = create_compatible_dc(); - prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); - gdi_draw_bitmap_redrop(canvas->dc, ©->src_area, bbox, dc, + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, copy->src_bitmap); + if (gdi_surface) { + Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, ©->mask); + set_scale_mode(canvas, copy->scale_mode); + set_clip(canvas, clip); + gdi_draw_bitmap_redrop(canvas->dc, ©->src_area, bbox, gdi_surface->dc, &bitmapmask, copy->rop_decriptor, 0); - SelectObject(dc, prev_bitmap); - DeleteObject(dc); - ReleaseMutex(pixman_data->mutex); } else { - surface_to_image(surface, &image); - gdi_draw_image(canvas->dc, ©->src_area, bbox, image.pixels, - image.stride, image.width, image.height, &bitmapmask, - copy->rop_decriptor, 0); - } + surface = canvas_get_image(&canvas->base, copy->src_bitmap); + pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); + + Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, ©->mask); + set_scale_mode(canvas, copy->scale_mode); + set_clip(canvas, clip); + + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + HDC dc; + HBITMAP prev_bitmap; + + dc = create_compatible_dc(); + prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); + gdi_draw_bitmap_redrop(canvas->dc, ©->src_area, bbox, dc, + &bitmapmask, copy->rop_decriptor, 0); + SelectObject(dc, prev_bitmap); + DeleteObject(dc); + ReleaseMutex(pixman_data->mutex); + } else { + surface_to_image(surface, &image); + gdi_draw_image(canvas->dc, ©->src_area, bbox, image.pixels, + image.stride, image.width, image.height, &bitmapmask, + copy->rop_decriptor, 0); + } + pixman_image_unref(surface); + + } free_mask(&bitmapmask); - - pixman_image_unref(surface); } static void gdi_canvas_put_image(SpiceCanvas *spice_canvas, HDC dc, const SpiceRect *dest, const uint8_t *src_data, @@ -1136,34 +1186,43 @@ static void gdi_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bb SpiceTransparent* transparent) { GdiCanvas *canvas = (GdiCanvas *)spice_canvas; + GdiCanvas *gdi_surface; pixman_image_t *surface; GdiImage image; PixmanData *pixman_data; - surface = canvas_get_image(&canvas->base, transparent->src_bitmap); - pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); - Lock lock(*canvas->lock); - set_clip(canvas, clip); - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - HDC dc; - HBITMAP prev_bitmap; - - dc = create_compatible_dc(); - prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); - gdi_draw_bitmap_transparent(canvas, canvas->dc, &transparent->src_area, bbox, dc, - transparent->true_color); - - SelectObject(dc, prev_bitmap); - DeleteObject(dc); - ReleaseMutex(pixman_data->mutex); + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, transparent->src_bitmap); + if (gdi_surface) { + Lock lock(*canvas->lock); + set_clip(canvas, clip); + gdi_draw_bitmap_transparent(canvas, canvas->dc, &transparent->src_area, bbox, + gdi_surface->dc, transparent->true_color); } else { - surface_to_image(surface, &image); - gdi_draw_image_transparent(canvas, canvas->dc, &transparent->src_area, bbox, image.pixels, - image.stride, image.width, image.height, - transparent->true_color, 0); + surface = canvas_get_image(&canvas->base, transparent->src_bitmap); + pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); + Lock lock(*canvas->lock); + set_clip(canvas, clip); + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + HDC dc; + HBITMAP prev_bitmap; + + dc = create_compatible_dc(); + prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); + gdi_draw_bitmap_transparent(canvas, canvas->dc, &transparent->src_area, bbox, dc, + transparent->true_color); + + SelectObject(dc, prev_bitmap); + DeleteObject(dc); + ReleaseMutex(pixman_data->mutex); + } else { + surface_to_image(surface, &image); + gdi_draw_image_transparent(canvas, canvas->dc, &transparent->src_area, bbox, image.pixels, + image.stride, image.width, image.height, + transparent->true_color, 0); + } + + pixman_image_unref(surface); } - - pixman_image_unref(surface); } static void gdi_draw_bitmap_alpha(HDC dest_dc, const SpiceRect *src, const SpiceRect *dest, @@ -1208,40 +1267,51 @@ static void gdi_draw_image_alpha(HDC dest_dc, const SpiceRect *src, const SpiceR static void gdi_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlnd* alpha_blend) { GdiCanvas *canvas = (GdiCanvas *)spice_canvas; + GdiCanvas *gdi_surface; pixman_image_t *surface; GdiImage image; PixmanData *pixman_data; int use_bitmap_alpha; - surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap); - use_bitmap_alpha = pixman_image_get_depth(surface) == 32; - pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); - - Lock lock(*canvas->lock); - set_clip(canvas, clip); - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - HDC dc; - HBITMAP prev_bitmap; - - dc = create_compatible_dc(); - prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); - gdi_draw_bitmap_alpha(canvas->dc, &alpha_blend->src_area, bbox, dc, alpha_blend->alpha, - use_bitmap_alpha); - SelectObject(dc, prev_bitmap); - DeleteObject(dc); - ReleaseMutex(pixman_data->mutex); + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, alpha_blend->src_bitmap); + if (gdi_surface) { + Lock lock(*canvas->lock); + set_clip(canvas, clip); + use_bitmap_alpha = 0; + gdi_draw_bitmap_alpha(canvas->dc, &alpha_blend->src_area, bbox, gdi_surface->dc, + alpha_blend->alpha, use_bitmap_alpha); } else { - surface_to_image(surface, &image); - gdi_draw_image_alpha(canvas->dc, &alpha_blend->src_area, bbox, image.pixels, - image.stride, image.width, image.height, - alpha_blend->alpha, 0, use_bitmap_alpha); + surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap); + use_bitmap_alpha = pixman_image_get_depth(surface) == 32; + pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); + + Lock lock(*canvas->lock); + set_clip(canvas, clip); + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + HDC dc; + HBITMAP prev_bitmap; + + dc = create_compatible_dc(); + prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); + gdi_draw_bitmap_alpha(canvas->dc, &alpha_blend->src_area, bbox, dc, alpha_blend->alpha, + use_bitmap_alpha); + SelectObject(dc, prev_bitmap); + DeleteObject(dc); + ReleaseMutex(pixman_data->mutex); + } else { + surface_to_image(surface, &image); + gdi_draw_image_alpha(canvas->dc, &alpha_blend->src_area, bbox, image.pixels, + image.stride, image.width, image.height, + alpha_blend->alpha, 0, use_bitmap_alpha); + } + + pixman_image_unref(surface); } - - pixman_image_unref(surface); } static void gdi_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque) { + GdiCanvas *gdi_surface; GdiCanvas *canvas = (GdiCanvas *)spice_canvas; pixman_image_t *surface; GdiImage image; @@ -1251,77 +1321,98 @@ static void gdi_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, S HBRUSH hbrush; uint8_t rop3; - surface = canvas_get_image(&canvas->base, opaque->src_bitmap); - pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); - bitmapmask = get_mask_bitmap(canvas, &opaque->mask); rop3 = calc_rop3_src_brush(opaque->rop_decriptor); - hbrush = get_brush(canvas, &opaque->brush); - - Lock lock(*canvas->lock); - set_scale_mode(canvas, opaque->scale_mode); - set_clip(canvas, clip); - prev_hbrush = set_brush(canvas->dc, hbrush, &opaque->brush); - - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - HDC dc; - HBITMAP prev_bitmap; - - dc = create_compatible_dc(); - prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); - gdi_draw_bitmap(canvas->dc, &opaque->src_area, bbox, dc, &bitmapmask, rop3); - SelectObject(dc, prev_bitmap); - DeleteObject(dc); - ReleaseMutex(pixman_data->mutex); + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, opaque->src_bitmap); + if (gdi_surface) { + Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &opaque->mask); + hbrush = get_brush(canvas, &opaque->brush); + set_scale_mode(canvas, opaque->scale_mode); + set_clip(canvas, clip); + prev_hbrush = set_brush(canvas->dc, hbrush, &opaque->brush); + gdi_draw_bitmap(canvas->dc, &opaque->src_area, bbox, gdi_surface->dc, &bitmapmask, rop3); + unset_brush(canvas->dc, prev_hbrush); } else { - surface_to_image(surface, &image); - gdi_draw_image_rop3(canvas->dc, &opaque->src_area, bbox, image.pixels, - image.stride, image.width, image.height, &bitmapmask, rop3, 0); + surface = canvas_get_image(&canvas->base, opaque->src_bitmap); + pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); + + Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &opaque->mask); + hbrush = get_brush(canvas, &opaque->brush); + set_scale_mode(canvas, opaque->scale_mode); + set_clip(canvas, clip); + prev_hbrush = set_brush(canvas->dc, hbrush, &opaque->brush); + + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + HDC dc; + HBITMAP prev_bitmap; + + dc = create_compatible_dc(); + prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); + gdi_draw_bitmap(canvas->dc, &opaque->src_area, bbox, dc, &bitmapmask, rop3); + SelectObject(dc, prev_bitmap); + DeleteObject(dc); + ReleaseMutex(pixman_data->mutex); + } else { + surface_to_image(surface, &image); + gdi_draw_image_rop3(canvas->dc, &opaque->src_area, bbox, image.pixels, + image.stride, image.width, image.height, &bitmapmask, rop3, 0); + } + unset_brush(canvas->dc, prev_hbrush); + pixman_image_unref(surface); } - unset_brush(canvas->dc, prev_hbrush); - free_mask(&bitmapmask); - - pixman_image_unref(surface); } static void gdi_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend) { + GdiCanvas *gdi_surface; GdiCanvas *canvas = (GdiCanvas *)spice_canvas; pixman_image_t *surface; GdiImage image; struct BitmapData bitmapmask; PixmanData *pixman_data; - bitmapmask = get_mask_bitmap(canvas, &blend->mask); - surface = canvas_get_image(&canvas->base, blend->src_bitmap); - pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); - - Lock lock(*canvas->lock); - set_scale_mode(canvas, blend->scale_mode); - set_clip(canvas, clip); - - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - HDC dc; - HBITMAP prev_bitmap; - - dc = create_compatible_dc(); - prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); - gdi_draw_bitmap_redrop(canvas->dc, &blend->src_area, bbox, dc, + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, blend->src_bitmap); + if (gdi_surface) { + Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &blend->mask); + set_scale_mode(canvas, blend->scale_mode); + set_clip(canvas, clip); + gdi_draw_bitmap_redrop(canvas->dc, &blend->src_area, bbox, gdi_surface->dc, &bitmapmask, blend->rop_decriptor, 0); - SelectObject(dc, prev_bitmap); - DeleteObject(dc); - ReleaseMutex(pixman_data->mutex); - } else { - surface_to_image(surface, &image); - gdi_draw_image(canvas->dc, &blend->src_area, bbox, image.pixels, image.stride, image.width, - image.height, &bitmapmask, blend->rop_decriptor, 0); + } else { + surface = canvas_get_image(&canvas->base, blend->src_bitmap); + pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); + + Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &blend->mask); + set_scale_mode(canvas, blend->scale_mode); + set_clip(canvas, clip); + + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + HDC dc; + HBITMAP prev_bitmap; + + dc = create_compatible_dc(); + prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); + gdi_draw_bitmap_redrop(canvas->dc, &blend->src_area, bbox, dc, + &bitmapmask, blend->rop_decriptor, 0); + SelectObject(dc, prev_bitmap); + DeleteObject(dc); + ReleaseMutex(pixman_data->mutex); + } else { + surface_to_image(surface, &image); + gdi_draw_image(canvas->dc, &blend->src_area, bbox, image.pixels, image.stride, image.width, + image.height, &bitmapmask, blend->rop_decriptor, 0); + } + + pixman_image_unref(surface); } free_mask(&bitmapmask); - - pixman_image_unref(surface); } static void gdi_canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness) @@ -1329,9 +1420,8 @@ static void gdi_canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox GdiCanvas *canvas = (GdiCanvas *)spice_canvas; struct BitmapData bitmapmask; - bitmapmask = get_mask_bitmap(canvas, &blackness->mask); - Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &blackness->mask); set_clip(canvas, clip); gdi_draw_bitmap(canvas->dc, bbox, bbox, canvas->dc, &bitmapmask, 0x0); @@ -1343,9 +1433,8 @@ static void gdi_canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, S GdiCanvas *canvas = (GdiCanvas *)spice_canvas; struct BitmapData bitmapmask; - bitmapmask = get_mask_bitmap(canvas, &invers->mask); - Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &invers->mask); set_clip(canvas, clip); gdi_draw_bitmap(canvas->dc, bbox, bbox, canvas->dc, &bitmapmask, 0x55); @@ -1357,9 +1446,8 @@ static void gdi_canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox GdiCanvas *canvas = (GdiCanvas *)spice_canvas; struct BitmapData bitmapmask; - bitmapmask = get_mask_bitmap(canvas, &whiteness->mask); - Lock lock(*canvas->lock); + bitmapmask = get_mask_bitmap(canvas, &whiteness->mask); set_clip(canvas, clip); gdi_draw_bitmap(canvas->dc, bbox, bbox, canvas->dc, &bitmapmask, 0xff); @@ -1368,6 +1456,7 @@ static void gdi_canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox static void gdi_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3) { + GdiCanvas *gdi_surface; GdiCanvas *canvas = (GdiCanvas *)spice_canvas; pixman_image_t *surface; GdiImage image; @@ -1376,37 +1465,49 @@ static void gdi_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi HBRUSH hbrush; PixmanData *pixman_data; - hbrush = get_brush(canvas, &rop3->brush); - surface = canvas_get_image(&canvas->base, rop3->src_bitmap); - pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); - bitmapmask = get_mask_bitmap(canvas, &rop3->mask); - - Lock lock(*canvas->lock); - set_scale_mode(canvas, rop3->scale_mode); - set_clip(canvas, clip); - prev_hbrush = set_brush(canvas->dc, hbrush, &rop3->brush); - - if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { - HDC dc; - HBITMAP prev_bitmap; - - dc = create_compatible_dc(); - prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); - gdi_draw_bitmap(canvas->dc, &rop3->src_area, bbox, dc, + gdi_surface = (GdiCanvas *)canvas_get_surface(&canvas->base, rop3->src_bitmap); + if (gdi_surface) { + Lock lock(*canvas->lock); + hbrush = get_brush(canvas, &rop3->brush); + bitmapmask = get_mask_bitmap(canvas, &rop3->mask); + set_scale_mode(canvas, rop3->scale_mode); + set_clip(canvas, clip); + prev_hbrush = set_brush(canvas->dc, hbrush, &rop3->brush); + gdi_draw_bitmap(canvas->dc, &rop3->src_area, bbox, gdi_surface->dc, &bitmapmask, rop3->rop3); - SelectObject(dc, prev_bitmap); - DeleteObject(dc); - ReleaseMutex(pixman_data->mutex); + unset_brush(canvas->dc, prev_hbrush); } else { - surface_to_image(surface, &image); - gdi_draw_image_rop3(canvas->dc, &rop3->src_area, bbox, image.pixels, - image.stride, image.width, image.height, &bitmapmask, rop3->rop3, 0); + surface = canvas_get_image(&canvas->base, rop3->src_bitmap); + pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface); + Lock lock(*canvas->lock); + hbrush = get_brush(canvas, &rop3->brush); + bitmapmask = get_mask_bitmap(canvas, &rop3->mask); + set_scale_mode(canvas, rop3->scale_mode); + set_clip(canvas, clip); + prev_hbrush = set_brush(canvas->dc, hbrush, &rop3->brush); + + if (pixman_data && (WaitForSingleObject(pixman_data->mutex, INFINITE) != WAIT_FAILED)) { + HDC dc; + HBITMAP prev_bitmap; + + dc = create_compatible_dc(); + prev_bitmap = (HBITMAP)SelectObject(dc, pixman_data->bitmap); + gdi_draw_bitmap(canvas->dc, &rop3->src_area, bbox, dc, + &bitmapmask, rop3->rop3); + SelectObject(dc, prev_bitmap); + DeleteObject(dc); + ReleaseMutex(pixman_data->mutex); + } else { + surface_to_image(surface, &image); + gdi_draw_image_rop3(canvas->dc, &rop3->src_area, bbox, image.pixels, + image.stride, image.width, image.height, &bitmapmask, rop3->rop3, 0); + } + + unset_brush(canvas->dc, prev_hbrush); + pixman_image_unref(surface); } - unset_brush(canvas->dc, prev_hbrush); free_mask(&bitmapmask); - - pixman_image_unref(surface); } static void gdi_canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos) @@ -1433,8 +1534,8 @@ static void gdi_canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi HBRUSH prev_hbrush; HBRUSH hbrush; - hbrush = get_brush(canvas, &text->back_brush); Lock lock(*canvas->lock); + hbrush = get_brush(canvas, &text->back_brush); prev_hbrush = set_brush(canvas->dc, hbrush, &text->back_brush); gdi_draw_bitmap_redrop(canvas->dc, bbox, bbox, canvas->dc, NULL, text->back_mode, 1); @@ -1724,6 +1825,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height, #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , SpiceImageCache *bits_cache #endif + , SpiceImageSurfaces *surfaces , SpiceGlzDecoder *glz_decoder ) { @@ -1742,6 +1844,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height, #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , bits_cache #endif + , surfaces , glz_decoder); canvas->dc = dc; canvas->lock = lock; diff --git a/common/gdi_canvas.h b/common/gdi_canvas.h index 8b8f847d..73d6978e 100644 --- a/common/gdi_canvas.h +++ b/common/gdi_canvas.h @@ -37,6 +37,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height, HDC dc, class Mutex *lock, int bits, SpiceImageCache *bits_cache, SpicePaletteCache *palette_cache, + SpiceImageSurfaces *surfaces, SpiceGlzDecoder *glz_decoder); void gdi_canvas_init(); diff --git a/common/gl_canvas.c b/common/gl_canvas.c index f69c920b..3fd49f24 100644 --- a/common/gl_canvas.c +++ b/common/gl_canvas.c @@ -828,6 +828,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, int depth #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , SpiceImageCache *bits_cache #endif + , SpiceImageSurfaces *surfaces , SpiceGlzDecoder *glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , SpiceVirtMapping *virt_mapping @@ -854,6 +855,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, int depth #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , bits_cache #endif + , surfaces , glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , virt_mapping diff --git a/common/gl_canvas.h b/common/gl_canvas.h index 29737ec8..6d236292 100644 --- a/common/gl_canvas.h +++ b/common/gl_canvas.h @@ -28,6 +28,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, int depth #elif defined(CAIRO_CANVAS_IMAGE_CACHE) , SpiceImageCache *bits_cache #endif + , SpiceImageSurfaces *surfaces , SpiceGlzDecoder *glz_decoder #ifndef CAIRO_CANVAS_NO_CHUNKS , SpiceVirtMapping *virt_mapping diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c index 17bf24cf..88059f6e 100644 --- a/server/red_dispatcher.c +++ b/server/red_dispatcher.c @@ -522,6 +522,7 @@ RedDispatcher *red_dispatcher_init(QXLInterface *qxl_interface) init_data.num_memslots = init_info.num_memslots; init_data.num_memslots_groups = init_info.num_memslots_groups; init_data.internal_groupslot_id = init_info.internal_groupslot_id; + init_data.n_surfaces = init_info.n_surfaces; num_active_workers = 1; diff --git a/server/red_worker.c b/server/red_worker.c index 5dec5f67..6d19f352 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -396,6 +396,7 @@ typedef struct ImageItem { int height; int stride; int top_down; + int surface_id; uint8_t data[0]; } ImageItem; @@ -460,6 +461,7 @@ typedef struct __attribute__ ((__packed__)) RedImage { SpiceQUICData quic; SpiceLZRGBData lz_rgb; SpiceLZPLTData lz_plt; + SpiceSurface surface; }; } RedImage; @@ -612,6 +614,8 @@ typedef struct GlzSharedDictionary { int migrate_freeze; } GlzSharedDictionary; +#define NUM_SURFACES 10000 + struct DisplayChannel { RedChannel base; @@ -639,7 +643,7 @@ struct DisplayChannel { Ring glz_drawables_inst_to_free; // list of instances to be freed pthread_mutex_t glz_drawables_inst_to_free_lock; - uint8_t surface_client_created; + uint8_t surface_client_created[NUM_SURFACES]; struct { union { @@ -798,8 +802,14 @@ typedef enum { BITMAP_GRADUAL_HIGH, } BitmapGradualType; +typedef struct DependItem { + Drawable *drawable; + RingItem ring_item; +} DependItem; + struct Drawable { uint8_t refs; + RingItem surface_list_link; RingItem list_link; DrawItem tree_item; PipeItem pipe_item; @@ -821,6 +831,10 @@ struct Drawable { BitmapGradualType copy_bitmap_graduality; uint32_t group_id; uint8_t *self_bitmap; + DependItem depend_items[3]; + + uint8_t *backed_surface_data; + DependItem pipe_depend_items[3]; }; typedef struct _Drawable _Drawable; @@ -860,7 +874,16 @@ typedef struct DrawContext { typedef struct RedSurface { uint32_t refs; + Ring current; + Ring current_list; + int current_gn; DrawContext context; + + Ring depend_on_me; + + //fix me - better handling here + QXLReleaseInfo *release_info; + uint32_t release_group_id; } RedSurface; #ifdef STREAM_TRACE @@ -907,10 +930,11 @@ typedef struct RedWorker { uint32_t renderers[RED_MAX_RENDERERS]; uint32_t renderer; - RedSurface surface; + RedSurface surfaces[NUM_SURFACES]; + uint32_t n_surfaces; + SpiceImageSurfaces image_surfaces; Ring current_list; - Ring current; uint32_t current_size; uint32_t drawable_count; uint32_t transparent_count; @@ -990,14 +1014,14 @@ typedef struct RedWorker { pthread_mutex_t avcodec_lock = PTHREAD_MUTEX_INITIALIZER; static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable); -static void red_current_flush(RedWorker *worker); +static void red_current_flush(RedWorker *worker, int surface_id); static void display_channel_push(RedWorker *worker); #ifdef DRAW_ALL -#define red_update_area(worker, rect) +#define red_update_area(worker, rect, surface_id) #define red_draw_drawable(worker, item) #else static void red_draw_drawable(RedWorker *worker, Drawable *item); -static void red_update_area(RedWorker *worker, const SpiceRect *area); +static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id); #endif static void red_release_cursor(RedWorker *worker, CursorItem *cursor); static inline void release_drawable(RedWorker *worker, Drawable *item); @@ -1070,6 +1094,25 @@ static void print_compress_stats(DisplayChannel *display_channel) #endif +static inline int is_primary_surface(RedWorker *worker, uint32_t surface_id) +{ + if (surface_id == 0) { + return TRUE; + } + return FALSE; +} + +static inline void __validate_surface(RedWorker *worker, uint32_t surface_id) +{ + PANIC_ON(surface_id >= worker->n_surfaces); +} + +static inline void validate_surface(RedWorker *worker, uint32_t surface_id) +{ + PANIC_ON(surface_id >= worker->n_surfaces); + PANIC_ON(!worker->surfaces[surface_id].context.canvas); +} + static inline int get_memslot_id(RedWorker *worker, unsigned long addr) { return addr >> worker->memslot_id_shift; @@ -1345,11 +1388,45 @@ static void red_pipe_add_type(RedChannel* channel, int pipe_item_type) red_pipe_add(channel, item); } +static inline void red_create_surface_item(RedWorker *worker, int surface_id); +static void red_add_surface_image(RedWorker *worker, int surface_id); + +static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker, Drawable *drawable) +{ + int x; + int surface_id; + + for (x = 0; x < 3; ++x) { + surface_id = drawable->qxl_drawable->surfaces_dest[x]; + if (surface_id != -1) { + validate_surface(worker, surface_id); + if (worker->display_channel->surface_client_created[surface_id] == TRUE) { + continue; + } + red_create_surface_item(worker, surface_id); + red_add_surface_image(worker, surface_id); + } + } + + surface_id = drawable->qxl_drawable->surface_id; + validate_surface(worker, surface_id); + + if (worker->display_channel->surface_client_created[surface_id] == TRUE) { + return; + } + + red_create_surface_item(worker, surface_id); + red_add_surface_image(worker, surface_id); +} + static inline void red_pipe_add_drawable(RedWorker *worker, Drawable *drawable) { if (!worker->display_channel) { return; } + + red_handle_drawable_surfaces_client_synced(worker, drawable); + drawable->refs++; red_pipe_add(&worker->display_channel->base, &drawable->pipe_item); } @@ -1369,6 +1446,8 @@ static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *draw red_pipe_add_after(&worker->display_channel->base, &drawable->pipe_item, &pos_after->pipe_item); } +static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id); + static inline void red_pipe_remove_drawable(RedWorker *worker, Drawable *drawable) { if (ring_item_is_linked(&drawable->pipe_item.link)) { @@ -1435,8 +1514,6 @@ static void red_pipe_clear(RedChannel *channel) case PIPE_ITEM_TYPE_MIGRATE_DATA: case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE: case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE: - case PIPE_ITEM_TYPE_CREATE_SURFACE: - case PIPE_ITEM_TYPE_DESTROY_SURFACE: free(item); break; case PIPE_ITEM_TYPE_IMAGE: @@ -1453,6 +1530,18 @@ static void red_pipe_clear(RedChannel *channel) red_display_release_stream((DisplayChannel *)channel, SPICE_CONTAINEROF(item, StreamAgent, destroy_item)); break; + case PIPE_ITEM_TYPE_CREATE_SURFACE: { + SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(item, SurfaceCreateItem, + pipe_item); + free(surface_create); + break; + } + case PIPE_ITEM_TYPE_DESTROY_SURFACE: { + SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(item, SurfaceDestroyItem, + pipe_item); + free(surface_destroy); + break; + } } } channel->pipe_size = 0; @@ -1532,40 +1621,62 @@ static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_ return; } + worker->display_channel->surface_client_created[surface_id] = FALSE; + destroy = get_surface_destroy_item(surface_id); red_pipe_add(&worker->display_channel->base, &destroy->pipe_item); } -static inline void __red_destroy_surface(RedWorker *worker) +static inline void __red_destroy_surface(RedWorker *worker, uint32_t surface_id) { - RedSurface *surface = &worker->surface; + RedSurface *surface = &worker->surfaces[surface_id]; - if (!--worker->surface.refs) { + if (!--surface->refs) { #ifdef STREAM_TRACE red_reset_stream_trace(worker); #endif if (surface->context.canvas) { surface->context.canvas->ops->destroy(surface->context.canvas); + if (surface->release_info) { + QXLReleaseInfoExt release_info_ext; + + release_info_ext.group_id = surface->release_group_id; + release_info_ext.info = surface->release_info; + worker->qxl->release_resource(worker->qxl, release_info_ext); + } + surface->context.canvas = NULL; - red_destroy_surface_item(worker, 0); + red_destroy_surface_item(worker, surface_id); } + + PANIC_ON(!ring_is_empty(&surface->depend_on_me)); } } -static inline void red_destroy_surface(RedWorker *worker) +static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id) +{ + validate_surface(worker, surface_id); + __red_destroy_surface(worker, surface_id); +} + +static inline void set_surface_release_info(RedWorker *worker, uint32_t surface_id, + QXLReleaseInfo *release_info, uint32_t group_id) { - RedSurface *surface = &worker->surface; + RedSurface *surface; - PANIC_ON(!surface->context.canvas); - __red_destroy_surface(worker); + validate_surface(worker, surface_id); + surface = &worker->surfaces[surface_id]; + + surface->release_info = release_info; + surface->release_group_id = group_id; } static inline void free_qxl_drawable(RedWorker *worker, QXLDrawable *drawable, uint32_t group_id, uint8_t *self_bitmap) { QXLReleaseInfoExt release_info_ext; - red_destroy_surface(worker); + red_destroy_surface(worker, drawable->surface_id); if (self_bitmap) { free(self_bitmap); @@ -1575,6 +1686,41 @@ static inline void free_qxl_drawable(RedWorker *worker, QXLDrawable *drawable, u worker->qxl->release_resource(worker->qxl, release_info_ext); } +static void remove_depended_item(DependItem *item) +{ + ASSERT(item->drawable); + ASSERT(ring_item_is_linked(&item->ring_item)); + item->drawable = NULL; + ring_remove(&item->ring_item); +} + +static inline void red_dec_surfaces_drawable_dependencies(RedWorker *worker, QXLDrawable *drawable) +{ + int x; + int surface_id; + + for (x = 0; x < 3; ++x) { + surface_id = drawable->surfaces_dest[x]; + if (surface_id == -1) { + continue; + } + red_destroy_surface(worker, surface_id); + } +} + +static void remove_drawable_dependencies(RedWorker *worker, Drawable *drawable) +{ + int x; + int surface_id; + + for (x = 0; x < 3; ++x) { + surface_id = drawable->qxl_drawable->surfaces_dest[x]; + if (surface_id != -1 && drawable->depend_items[x].drawable) { + remove_depended_item(&drawable->depend_items[x]); + } + } +} + static inline void release_drawable(RedWorker *worker, Drawable *item) { if (!--item->refs) { @@ -1588,6 +1734,9 @@ static inline void release_drawable(RedWorker *worker, Drawable *item) ASSERT(!item->tree_item.shadow); region_destroy(&item->tree_item.base.rgn); + remove_drawable_dependencies(worker, item); + red_dec_surfaces_drawable_dependencies(worker, item->qxl_drawable); + if (item->red_glz_drawable) { item->red_glz_drawable->drawable = NULL; } else { // no refernce to the qxl drawable left @@ -1659,9 +1808,29 @@ static inline void red_add_item_trace(RedWorker *worker, Drawable *item) #endif +static void surface_flush(RedWorker *worker, int surface_id, SpiceRect *rect) +{ + red_update_area(worker, rect, surface_id); +} + +static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable) +{ + int x; + int surface_id; + + for (x = 0; x < 3; ++x) { + surface_id = drawable->qxl_drawable->surfaces_dest[x]; + if (surface_id != -1 && drawable->depend_items[x].drawable) { + remove_depended_item(&drawable->depend_items[x]); + surface_flush(worker, surface_id, &drawable->qxl_drawable->surfaces_rects[x]); + } + } +} + static inline void current_remove_drawable(RedWorker *worker, Drawable *item) { worker->drawable_count--; + if (item->tree_item.effect != QXL_EFFECT_OPAQUE) { worker->transparent_count--; } @@ -1675,6 +1844,7 @@ static inline void current_remove_drawable(RedWorker *worker, Drawable *item) remove_shadow(worker, &item->tree_item); ring_remove(&item->tree_item.base.siblings_link); ring_remove(&item->list_link); + ring_remove(&item->surface_list_link); release_drawable(worker, item); worker->current_size--; } @@ -1720,9 +1890,9 @@ static inline void current_remove(RedWorker *worker, TreeItem *item) } } -static void current_tree_for_each(RedWorker *worker, void (*f)(TreeItem *, void *), void * data) +static void current_tree_for_each(RedWorker *worker, Ring *ring, void (*f)(TreeItem *, void *), + void * data) { - Ring *ring = &worker->current; RingItem *ring_item; Ring *top_ring; @@ -1758,11 +1928,11 @@ static void current_tree_for_each(RedWorker *worker, void (*f)(TreeItem *, void } } -static void red_current_clear(RedWorker *worker) +static void red_current_clear(RedWorker *worker, int surface_id) { RingItem *ring_item; - while ((ring_item = ring_get_head(&worker->current))) { + while ((ring_item = ring_get_head(&worker->surfaces[surface_id].current))) { TreeItem *now = SPICE_CONTAINEROF(ring_item, TreeItem, siblings_link); current_remove(worker, now); } @@ -1840,19 +2010,19 @@ void __show_current(TreeItem *item, void *data) print_base_item("TREE", item); } -static void show_current(RedWorker *worker) +static void show_current(RedWorker *worker, Ring *ring) { - if (ring_is_empty(&worker->current)) { + if (ring_is_empty(ring)) { red_printf("TEST: TREE: EMPTY"); return; } - current_tree_for_each(worker, __show_current, NULL); + current_tree_for_each(worker, ring, __show_current, NULL); } #else #define print_rgn(a, b) #define print_draw_private(a, b) -#define show_current(a) +#define show_current(a, r) #define print_shadow_item(a, b) #define print_base_item(a, b) #endif @@ -1872,16 +2042,16 @@ static inline Shadow *__find_shadow(TreeItem *item) return ((DrawItem *)item)->shadow; } -static inline Ring *ring_of(RedWorker *worker, TreeItem *item) +static inline Ring *ring_of(RedWorker *worker, Ring *ring, TreeItem *item) { - return (item->container) ? &item->container->items : &worker->current; + return (item->container) ? &item->container->items : ring; } static inline int __contained_by(RedWorker *worker, TreeItem *item, Ring *ring) { ASSERT(item && ring); do { - Ring *now = ring_of(worker, item); + Ring *now = ring_of(worker, ring, item); if (now == ring) { return TRUE; } @@ -1890,7 +2060,7 @@ static inline int __contained_by(RedWorker *worker, TreeItem *item, Ring *ring) return FALSE; } -static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion *rgn, +static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *item, QRegion *rgn, Ring **top_ring, Drawable *frame_candidate) { QRegion and_rgn; @@ -1924,7 +2094,7 @@ static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion * region_or(rgn, &and_rgn); // in flat representation of current, shadow is always his owner next if (!__contained_by(worker, (TreeItem*)shadow, *top_ring)) { - *top_ring = ring_of(worker, (TreeItem*)shadow); + *top_ring = ring_of(worker, ring, (TreeItem*)shadow); } } } else { @@ -1944,7 +2114,7 @@ static inline void __exclude_region(RedWorker *worker, TreeItem *item, QRegion * if ((shadow = __find_shadow(item))) { region_or(rgn, &shadow->on_hold); if (!__contained_by(worker, (TreeItem*)shadow, *top_ring)) { - *top_ring = ring_of(worker, (TreeItem*)shadow); + *top_ring = ring_of(worker, ring, (TreeItem*)shadow); } } } @@ -1985,7 +2155,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q if (region_intersects(rgn, &now->rgn)) { print_base_item("EXCLUDE2", now); - __exclude_region(worker, now, rgn, &top_ring, frame_candidate); + __exclude_region(worker, ring, now, rgn, &top_ring, frame_candidate); print_base_item("EXCLUDE3", now); if (region_is_empty(&now->rgn)) { @@ -2048,7 +2218,7 @@ static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, Q if (region_test(rgn, &now->rgn, REGION_TEST_SHARED)) { print_base_item("EXCLUDE2", now); - __exclude_region(worker, now, rgn, &top_ring); + __exclude_region(worker, ring, now, rgn, &top_ring); print_base_item("EXCLUDE3", now); if (region_is_empty(&now->rgn)) { @@ -2115,8 +2285,14 @@ static inline int is_opaque_item(TreeItem *item) static inline void __current_add_drawable(RedWorker *worker, Drawable *drawable, RingItem *pos) { + RedSurface *surface; + uint32_t surface_id = drawable->qxl_drawable->surface_id; + + validate_surface(worker, surface_id); + surface = &worker->surfaces[surface_id]; ring_add_after(&drawable->tree_item.base.siblings_link, pos); ring_add(&worker->current_list, &drawable->list_link); + ring_add(&surface->current_list, &drawable->surface_list_link); drawable->refs++; } @@ -3163,14 +3339,13 @@ static void red_reset_stream_trace(RedWorker *worker) #endif -static inline int red_current_add(RedWorker *worker, Drawable *drawable) +static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawable) { DrawItem *item = &drawable->tree_item; #ifdef RED_WORKER_STAT stat_time_t start_time = stat_now(); #endif RingItem *now; - Ring *ring = &worker->current; QRegion exclude_rgn; RingItem *exclude_base = NULL; @@ -3284,10 +3459,10 @@ static inline int red_current_add(RedWorker *worker, Drawable *drawable) #else -static inline void __handle_remove_shadow(RedWorker *worker, TreeItem *item) +static inline void __handle_remove_shadow(RedWorker *worker, TreeItem *item, Ring *ring) { Shadow *shadow; - Ring *ring; + Ring *_ring; while (item->type == TREE_ITEM_TYPE_CONTAINER) { if (!(item = (TreeItem *)ring_get_tail(&((Container *)item)->items))) { @@ -3299,19 +3474,18 @@ static inline void __handle_remove_shadow(RedWorker *worker, TreeItem *item) return; } print_base_item("SHADW", &shadow->base); - ring = (shadow->base.container) ? &shadow->base.container->items : &worker->current; - exclude_region(worker, ring, ring_next(ring, &shadow->base.siblings_link), &shadow->on_hold); + _ring = (shadow->base.container) ? &shadow->base.container->items : ring; + exclude_region(worker, _ring, ring_next(_ring, &shadow->base.siblings_link), &shadow->on_hold); region_clear(&shadow->on_hold); } -static inline int red_current_add(RedWorker *worker, Drawable *drawable) +static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawable) { DrawItem *item = &drawable->tree_item; #ifdef RED_WORKER_STAT stat_time_t start_time = stat_now(); #endif RingItem *now; - Ring *ring = &worker->current; print_base_item("ADD", &item->base); ASSERT(!region_is_empty(&item->base.rgn)); @@ -3430,12 +3604,11 @@ static inline Shadow *__new_shadow(RedWorker *worker, Drawable *item, SpicePoint return shadow; } -static inline int red_current_add_with_shadow(RedWorker *worker, Drawable *item, SpicePoint *delta) +static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Drawable *item, SpicePoint *delta) { #ifdef RED_WORKER_STAT stat_time_t start_time = stat_now(); #endif - Ring *ring; Shadow *shadow = __new_shadow(worker, item, delta); if (!shadow) { @@ -3444,7 +3617,6 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Drawable *item, } print_base_item("ADDSHADOW", &item->tree_item.base); worker->current_size++; - ring = &worker->current; // item and his shadow must initially be placed in the same container. // for now putting them on root. #ifdef STREAM_TRACE @@ -3518,7 +3690,7 @@ static inline void red_update_streamable(RedWorker *worker, Drawable *drawable, #endif -static inline int red_current_add_qxl(RedWorker *worker, Drawable *drawable, +static inline int red_current_add_qxl(RedWorker *worker, Ring *ring, Drawable *drawable, QXLDrawable *qxl_drawable) { int ret; @@ -3531,12 +3703,12 @@ static inline int red_current_add_qxl(RedWorker *worker, Drawable *drawable, #endif delta.x = qxl_drawable->u.copy_bits.src_pos.x - qxl_drawable->bbox.left; delta.y = qxl_drawable->u.copy_bits.src_pos.y - qxl_drawable->bbox.top; - ret = red_current_add_with_shadow(worker, drawable, &delta); + ret = red_current_add_with_shadow(worker, ring, drawable, &delta); } else { #ifdef STREAM_TRACE red_update_streamable(worker, drawable, qxl_drawable); #endif - ret = red_current_add(worker, drawable); + ret = red_current_add(worker, ring, drawable); } #ifdef RED_WORKER_STAT if ((++worker->add_count % 100) == 0) { @@ -3565,14 +3737,18 @@ static inline int red_current_add_qxl(RedWorker *worker, Drawable *drawable, return ret; } -static void red_get_area(RedWorker *worker, const SpiceRect *area, uint8_t *dest, int dest_stride, - int update) +static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *area, uint8_t *dest, + int dest_stride, int update) { - SpiceCanvas *canvas = worker->surface.context.canvas; + SpiceCanvas *canvas; + RedSurface *surface; + + surface = &worker->surfaces[surface_id]; if (update) { - red_update_area(worker, area); + red_update_area(worker, area, surface_id); } + canvas = surface->context.canvas; canvas->ops->read_bits(canvas, dest, dest_stride, area); } @@ -3583,11 +3759,18 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable) int32_t height; uint8_t *dest; int dest_stride; + uint32_t surface_id; + RedSurface *surface; if (!drawable->qxl_drawable->self_bitmap) { return TRUE; } + surface_id = drawable->qxl_drawable->surface_id; + validate_surface(worker, surface_id); + + surface = &worker->surfaces[surface_id]; + width = drawable->qxl_drawable->bbox.right - drawable->qxl_drawable->bbox.left; height = drawable->qxl_drawable->bbox.bottom - drawable->qxl_drawable->bbox.top; dest_stride = width * sizeof(uint32_t); @@ -3599,7 +3782,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable) image->descriptor.flags = 0; QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique); - image->bitmap.flags = QXL_BITMAP_DIRECT | (worker->surface.context.top_down ? + image->bitmap.flags = QXL_BITMAP_DIRECT | (surface->context.top_down ? QXL_BITMAP_TOP_DOWN : 0); image->bitmap.format = SPICE_BITMAP_FMT_32BIT; image->bitmap.stride = dest_stride; @@ -3608,7 +3791,8 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable) image->bitmap.data = (QXLPHYSICAL)dest; image->bitmap.palette = 0; - red_get_area(worker, &drawable->qxl_drawable->self_bitmap_area, dest, dest_stride, TRUE); + red_get_area(worker, surface_id, + &drawable->qxl_drawable->self_bitmap_area, dest, dest_stride, TRUE); drawable->self_bitmap = (uint8_t *)image; return TRUE; @@ -3628,6 +3812,7 @@ static void free_one_drawable(RedWorker *worker, int force_glz_free) } red_draw_drawable(worker, drawable); container = drawable->tree_item.base.container; + current_remove_drawable(worker, drawable); container_cleanup(worker, container); } @@ -3648,6 +3833,7 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qx drawable->tree_item.base.id = ++worker->last_id; #endif ring_item_init(&drawable->list_link); + ring_item_init(&drawable->surface_list_link); #ifdef UPDATE_AREA_BY_TREE ring_item_init(&drawable->collect_link); #endif @@ -3662,15 +3848,82 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, QXLDrawable *qx return drawable; } +static inline int red_handle_depends_on_target_surface(RedWorker *worker, uint32_t surface_id) +{ + RedSurface *surface; + RingItem *ring_item; + + validate_surface(worker, surface_id); + surface = &worker->surfaces[surface_id]; + + while ((ring_item = ring_get_tail(&surface->depend_on_me))) { + Drawable *drawable; + DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item); + drawable = depended_item->drawable; + surface_flush(worker, drawable->qxl_drawable->surface_id, &drawable->qxl_drawable->bbox); + } + + return TRUE; +} + +static inline void add_to_surface_dependency(RedWorker *worker, int depend_on_surface_id, + DependItem *depend_item, Drawable *drawable) +{ + RedSurface *surface; + + if (depend_on_surface_id == -1) { + depend_item->drawable = NULL; + return; + } + + validate_surface(worker, depend_on_surface_id); + surface = &worker->surfaces[depend_on_surface_id]; + + depend_item->drawable = drawable; + ring_add(&surface->depend_on_me, &depend_item->ring_item); +} + +static inline int red_handle_surfaces_dependencies(RedWorker *worker, Drawable *drawable) +{ + int x; + + for (x = 0; x < 3; ++x) { + add_to_surface_dependency(worker, drawable->qxl_drawable->surfaces_dest[x], + &drawable->depend_items[x], drawable); + } + + return TRUE; +} + +static inline void red_inc_surfaces_drawable_dependencies(RedWorker *worker, QXLDrawable *drawable) +{ + int x; + int surface_id; + RedSurface *surface; + + for (x = 0; x < 3; ++x) { + surface_id = drawable->surfaces_dest[x]; + if (surface_id == -1) { + continue; + } + validate_surface(worker, surface_id); + surface = &worker->surfaces[surface_id]; + surface->refs++; + } +} + static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable, uint32_t group_id) { + int surface_id; Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id); ASSERT(item); - PANIC_ON(!worker->surface.context.canvas); - ASSERT(worker->surface.refs != 0); - worker->surface.refs++; + surface_id = drawable->surface_id; + validate_surface(worker, surface_id); + + ASSERT(worker->surfaces[surface_id].refs != 0); + worker->surfaces[surface_id].refs++; region_add(&item->tree_item.base.rgn, &drawable->bbox); #ifdef PIPE_DEBUG @@ -3696,6 +3949,8 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable #endif } + red_inc_surfaces_drawable_dependencies(worker, drawable); + if (region_is_empty(&item->tree_item.base.rgn)) { release_drawable(worker, item); return; @@ -3706,7 +3961,18 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable return; } - if (red_current_add_qxl(worker, item, drawable)) { + if (!red_handle_depends_on_target_surface(worker, surface_id)) { + release_drawable(worker, item); + return; + } + + if (!red_handle_surfaces_dependencies(worker, item)) { + release_drawable(worker, item); + return; + } + + if (red_current_add_qxl(worker, &worker->surfaces[surface_id].current, item, + drawable)) { worker->drawable_count++; if (item->tree_item.effect != QXL_EFFECT_OPAQUE) { worker->transparent_count++; @@ -3719,6 +3985,49 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable release_drawable(worker, item); } +static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width, + uint32_t height, int32_t stride, uint8_t depth, void *line_0); + +static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface, uint32_t group_id) +{ + int surface_id; + RedSurface *red_surface; + uint8_t *data; + + surface_id = surface->surface_id; + __validate_surface(worker, surface_id); + + red_surface = &worker->surfaces[surface_id]; + + switch (surface->type) { + case QXL_SURFACE_CMD_CREATE: { + unsigned long saved_data = (unsigned long)surface->u.surface_create.data; + uint32_t height = surface->u.surface_create.height; + int32_t stride = surface->u.surface_create.stride; + QXLReleaseInfoExt release_info_ext; + + data = (uint8_t *)get_virt(worker, saved_data, height * abs(stride), group_id); + if (stride < 0) { + data -= (int32_t)(stride * (height - 1)); + } + red_create_surface(worker, surface_id, surface->u.surface_create.width, + height, stride, surface->u.surface_create.depth, data); + release_info_ext.group_id = group_id; + release_info_ext.info = &surface->release_info; + worker->qxl->release_resource(worker->qxl, release_info_ext); + break; + } + case QXL_SURFACE_CMD_DESTROY: + set_surface_release_info(worker, surface_id, &surface->release_info, group_id); + red_handle_depends_on_target_surface(worker, surface_id); + red_current_clear(worker, surface_id); + red_destroy_surface(worker, surface_id); + break; + default: + red_error("unknown surface command"); + }; +} + static void localize_path(RedWorker *worker, QXLPHYSICAL *in_path, uint32_t group_id) { QXLPath *path; @@ -3850,6 +4159,26 @@ static LocalImage *alloc_local_image(RedWorker *worker) return &worker->local_images[worker->local_images_pos++]; } +static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, + uint32_t surface_id) +{ + RedWorker *worker; + + worker = SPICE_CONTAINEROF(surfaces, RedWorker, image_surfaces); + validate_surface(worker, surface_id); + + return worker->surfaces[surface_id].context.canvas; +} + +static void image_surface_init(RedWorker *worker) +{ + static SpiceImageSurfacesOps image_surfaces_ops = { + image_surfaces_get, + }; + + worker->image_surfaces.ops = &image_surfaces_ops; +} + static ImageCacheItem *image_cache_find(ImageCache *cache, uint64_t id) { ImageCacheItem *item = cache->hash_table[id % IMAGE_CACHE_HASH_SIZE]; @@ -4070,6 +4399,9 @@ static void localize_bitmap(RedWorker *worker, QXLPHYSICAL *in_bitmap, uint32_t local_image->bitmap.palette = (SPICE_ADDRESS)shadow_palette; } break; + case SPICE_IMAGE_TYPE_SURFACE: { + break; + } default: red_error("invalid image type"); } @@ -4095,6 +4427,7 @@ static void unlocalize_bitmap(QXLPHYSICAL *bitmap) case SPICE_IMAGE_TYPE_QUIC: case SPICE_IMAGE_TYPE_FROM_CACHE: *bitmap = 0; + case SPICE_IMAGE_TYPE_SURFACE: break; default: red_error("invalid image type %u", image->descriptor.type); @@ -4154,8 +4487,16 @@ static void unlocalize_attr(SpiceLineAttr *attr) static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable) { + uint32_t surface_id; + RedSurface *surface; + SpiceCanvas *canvas; SpiceClip clip = drawable->qxl_drawable->clip; - SpiceCanvas *canvas = worker->surface.context.canvas; + + surface_id = drawable->qxl_drawable->surface_id; + validate_surface(worker, surface_id); + + surface = &worker->surfaces[surface_id]; + canvas = surface->context.canvas; worker->local_images_pos = 0; image_cache_eaging(&worker->image_cache); @@ -4295,24 +4636,30 @@ static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable) static void red_draw_drawable(RedWorker *worker, Drawable *drawable) { #ifdef UPDATE_AREA_BY_TREE - SpiceCanvas *canvas = worker->surface.context.canvas; + SpiceCanvas *canvas; + + canvas = surface->context.canvas; //todo: add need top mask flag canvas->ops->group_start(canvas, &drawable->tree_item.base.rgn); #endif + red_flush_source_surfaces(worker, drawable); red_draw_qxl_drawable(worker, drawable); #ifdef UPDATE_AREA_BY_TREE canvas->ops->group_end(canvas); #endif } -static void validate_area(RedWorker *worker, const SpiceRect *area) +static void validate_area(RedWorker *worker, const SpiceRect *area, uint32_t surface_id) { - if (!worker->surface.context.canvas_draws_on_surface) { - SpiceCanvas *canvas = worker->surface.context.canvas; + RedSurface *surface; + + surface = &worker->surfaces[surface_id]; + if (!surface->context.canvas_draws_on_surface) { + SpiceCanvas *canvas = surface->context.canvas; int h; - int stride = worker->surface.context.stride; - uint8_t *line_0 = worker->surface.context.line_0; + int stride = surface->context.stride; + uint8_t *line_0 = surface->context.line_0; if (!(h = area->bottom - area->top)) { return; @@ -4374,15 +4721,20 @@ static inline void __red_collect_for_update(RedWorker *worker, Ring *ring, RingI } } -static void red_update_area(RedWorker *worker, const SpiceRect *area) +static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id) { - Ring *ring = &worker->current; + RedSurface *surface; + Ring *ring; RingItem *ring_item; Ring items; QRegion rgn; + validate_surface(worker, surface_id); + surface = &worker->surfaces[surface_id]; + ring = &surface->current; + if (!(ring_item = ring_get_head(ring))) { - worker->draw_context.validate_area(worker->draw_context.canvas, + worker->draw_context.validate_area(surface->context.canvas, &worker->dev_info.surface0_area, area); return; } @@ -4403,23 +4755,34 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area) current_remove_drawable(worker, drawable); container_cleanup(worker, container); } - validate_area(worker, area); + validate_area(worker, area, surface_id); } #else -static void red_update_area(RedWorker *worker, const SpiceRect *area) +static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id) { - Ring *ring = &worker->current_list; - RingItem *ring_item = ring; + RedSurface *surface; + Ring *ring; + RingItem *ring_item; QRegion rgn; - Drawable *last = NULL; + Drawable *last; Drawable *now; + int gn; + + validate_surface(worker, surface_id); + surface = &worker->surfaces[surface_id]; + +start_again: + last = NULL; + gn = ++surface->current_gn; + ring = &surface->current_list; + ring_item = ring; region_init(&rgn); region_add(&rgn, area); while ((ring_item = ring_next(ring, ring_item))) { - now = SPICE_CONTAINEROF(ring_item, Drawable, list_link); + now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link); if (region_intersects(&rgn, &now->tree_item.base.rgn)) { last = now; break; @@ -4428,21 +4791,26 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area) region_destroy(&rgn); if (!last) { - validate_area(worker, area); + validate_area(worker, area, surface_id); return; } do { Container *container; - ring_item = ring_get_tail(&worker->current_list); - now = SPICE_CONTAINEROF(ring_item, Drawable, list_link); - red_draw_drawable(worker, now); + ring_item = ring_get_tail(&surface->current_list); + now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link); + now->refs++; container = now->tree_item.base.container; current_remove_drawable(worker, now); container_cleanup(worker, container); + red_draw_drawable(worker, now); + release_drawable(worker, now); + if (gn != surface->current_gn) { + goto start_again; + } } while (now != last); - validate_area(worker, area); + validate_area(worker, area, surface_id); } #endif @@ -4635,7 +5003,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size) QXLUpdateCmd *draw_cmd = (QXLUpdateCmd *)get_virt(worker, ext_cmd.cmd.data, sizeof(QXLUpdateCmd), ext_cmd.group_id); - red_update_area(worker, &draw_cmd->area); + red_update_area(worker, &draw_cmd->area, draw_cmd->surface_id); worker->qxl->notify_update(worker->qxl, draw_cmd->update_id); release_info_ext.group_id = ext_cmd.group_id; release_info_ext.info = &draw_cmd->release_info; @@ -4652,6 +5020,12 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size) worker->qxl->release_resource(worker->qxl, release_info_ext); break; } + case QXL_CMD_SURFACE: { + QXLSurfaceCmd *surface = (QXLSurfaceCmd *)get_virt(worker, ext_cmd.cmd.data, + sizeof(QXLSurfaceCmd), ext_cmd.group_id); + red_process_surface(worker, surface, ext_cmd.group_id); + break; + } default: red_error("bad command type"); } @@ -4687,40 +5061,43 @@ static void red_free_some(RedWorker *worker) } } -static void red_current_flush(RedWorker *worker) +static void red_current_flush(RedWorker *worker, int surface_id) { while (!ring_is_empty(&worker->current_list)) { free_one_drawable(worker, FALSE); } - red_current_clear(worker); + red_current_clear(worker, surface_id); } -static void red_add_screen_image(RedWorker *worker) +static void red_add_surface_image(RedWorker *worker, int surface_id) { ImageItem *item; int stride; SpiceRect area; - SpiceCanvas *canvas = worker->surface.context.canvas; + SpiceCanvas *canvas = worker->surfaces[surface_id].context.canvas; - if (!worker->display_channel || !canvas) { + if (!worker->display_channel || !worker->surfaces[surface_id].context.canvas) { return; } - stride = worker->surface.context.width << 2; - item = (ImageItem *)spice_malloc_n_m(worker->surface.context.height, stride, sizeof(ImageItem)); + stride = abs(worker->surfaces[surface_id].context.stride); + + item = (ImageItem *)spice_malloc_n_m(worker->surfaces[surface_id].context.height, stride, + sizeof(ImageItem)); red_pipe_item_init(&item->link, PIPE_ITEM_TYPE_IMAGE); item->refs = 1; + item->surface_id = surface_id; item->pos.x = item->pos.y = 0; - item->width = worker->surface.context.width; - item->height = worker->surface.context.height; + item->width = worker->surfaces[surface_id].context.width; + item->height = worker->surfaces[surface_id].context.height; item->stride = stride; - item->top_down = worker->surface.context.top_down; + item->top_down = worker->surfaces[surface_id].context.top_down; area.top = area.left = 0; - area.right = worker->surface.context.width; - area.bottom = worker->surface.context.height; + area.right = worker->surfaces[surface_id].context.width; + area.bottom = worker->surfaces[surface_id].context.height; canvas->ops->read_bits(canvas, item->data, stride, &area); red_pipe_add_image_item(worker, item); release_image_item(item); @@ -6047,6 +6424,23 @@ static void fill_bits(DisplayChannel *display_channel, QXLPHYSICAL *in_bitmap, D } switch (qxl_image->descriptor.type) { + case SPICE_IMAGE_TYPE_SURFACE: { + int surface_id; + RedSurface *surface; + + surface_id = qxl_image->surface_image.surface_id; + validate_surface(worker, surface_id); + + surface = &worker->surfaces[surface_id]; + image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE; + image->descriptor.flags = 0; + image->descriptor.width = surface->context.width; + image->descriptor.height = surface->context.height; + + image->surface.surface_id = surface_id; + add_buf(channel, BUF_TYPE_RAW, image, sizeof(SpiceSurfaceImage), 0, 0); + break; + } case SPICE_IMAGE_TYPE_BITMAP: #ifdef DUMP_BITMAP dump_bitmap(display_channel->base.worker, &qxl_image->bitmap, drawable->group_id); @@ -6214,7 +6608,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_FILL: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_FILL; fill_base(display_channel, &display_channel->send_data.u.fill.base, item, - sizeof(SpiceMsgDisplayDrawFill), 0); + sizeof(SpiceMsgDisplayDrawFill), drawable->surface_id); display_channel->send_data.u.fill.data = drawable->u.fill; fill_brush(display_channel, &display_channel->send_data.u.fill.data.brush, item); fill_mask(display_channel, &display_channel->send_data.u.fill.data.mask, item); @@ -6222,7 +6616,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_OPAQUE: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_OPAQUE; fill_base(display_channel, &display_channel->send_data.u.opaque.base, item, - sizeof(SpiceMsgDisplayDrawOpaque), 0); + sizeof(SpiceMsgDisplayDrawOpaque), drawable->surface_id); display_channel->send_data.u.opaque.data = drawable->u.opaque; fill_bits(display_channel, &display_channel->send_data.u.opaque.data.src_bitmap, item); fill_brush(display_channel, &display_channel->send_data.u.opaque.data.brush, item); @@ -6231,7 +6625,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_COPY: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_COPY; fill_base(display_channel, &display_channel->send_data.u.copy.base, item, - sizeof(SpiceMsgDisplayDrawCopy), 0); + sizeof(SpiceMsgDisplayDrawCopy), drawable->surface_id); display_channel->send_data.u.copy.data = drawable->u.copy; fill_bits(display_channel, &display_channel->send_data.u.copy.data.src_bitmap, item); fill_mask(display_channel, &display_channel->send_data.u.copy.data.mask, item); @@ -6239,27 +6633,27 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_TRANSPARENT: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_TRANSPARENT; fill_base(display_channel, &display_channel->send_data.u.transparent.base, item, - sizeof(SpiceMsgDisplayDrawTransparent), 0); + sizeof(SpiceMsgDisplayDrawTransparent), drawable->surface_id); display_channel->send_data.u.transparent.data = drawable->u.transparent; fill_bits(display_channel, &display_channel->send_data.u.transparent.data.src_bitmap, item); break; case QXL_DRAW_ALPHA_BLEND: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND; fill_base(display_channel, &display_channel->send_data.u.alpha_blend.base, item, - sizeof(SpiceMsgDisplayDrawAlphaBlend), 0); + sizeof(SpiceMsgDisplayDrawAlphaBlend), drawable->surface_id); display_channel->send_data.u.alpha_blend.data = drawable->u.alpha_blend; fill_bits(display_channel, &display_channel->send_data.u.alpha_blend.data.src_bitmap, item); break; case QXL_COPY_BITS: channel->send_data.header.type = SPICE_MSG_DISPLAY_COPY_BITS; fill_base(display_channel, &display_channel->send_data.u.copy_bits.base, item, - sizeof(SpiceMsgDisplayCopyBits), 0); + sizeof(SpiceMsgDisplayCopyBits), drawable->surface_id); display_channel->send_data.u.copy_bits.src_pos = drawable->u.copy_bits.src_pos; break; case QXL_DRAW_BLEND: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_BLEND; fill_base(display_channel, &display_channel->send_data.u.blend.base, item, - sizeof(SpiceMsgDisplayDrawBlend), 0); + sizeof(SpiceMsgDisplayDrawBlend), drawable->surface_id); display_channel->send_data.u.blend.data = drawable->u.blend; fill_bits(display_channel, &display_channel->send_data.u.blend.data.src_bitmap, item); fill_mask(display_channel, &display_channel->send_data.u.blend.data.mask, item); @@ -6267,28 +6661,28 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_BLACKNESS: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_BLACKNESS; fill_base(display_channel, &display_channel->send_data.u.blackness.base, item, - sizeof(SpiceMsgDisplayDrawBlackness), 0); + sizeof(SpiceMsgDisplayDrawBlackness), drawable->surface_id); display_channel->send_data.u.blackness.data = drawable->u.blackness; fill_mask(display_channel, &display_channel->send_data.u.blackness.data.mask, item); break; case QXL_DRAW_WHITENESS: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_WHITENESS; fill_base(display_channel, &display_channel->send_data.u.whiteness.base, item, - sizeof(SpiceMsgDisplayDrawWhiteness), 0); + sizeof(SpiceMsgDisplayDrawWhiteness), drawable->surface_id); display_channel->send_data.u.whiteness.data = drawable->u.whiteness; fill_mask(display_channel, &display_channel->send_data.u.whiteness.data.mask, item); break; case QXL_DRAW_INVERS: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_INVERS; fill_base(display_channel, &display_channel->send_data.u.invers.base, item, - sizeof(SpiceMsgDisplayDrawInvers), 0); + sizeof(SpiceMsgDisplayDrawInvers), drawable->surface_id); display_channel->send_data.u.invers.data = drawable->u.invers; fill_mask(display_channel, &display_channel->send_data.u.invers.data.mask, item); break; case QXL_DRAW_ROP3: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_ROP3; fill_base(display_channel, &display_channel->send_data.u.rop3.base, item, - sizeof(SpiceMsgDisplayDrawRop3), 0); + sizeof(SpiceMsgDisplayDrawRop3), drawable->surface_id); display_channel->send_data.u.rop3.data = drawable->u.rop3; fill_bits(display_channel, &display_channel->send_data.u.rop3.data.src_bitmap, item); fill_brush(display_channel, &display_channel->send_data.u.rop3.data.brush, item); @@ -6297,7 +6691,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_STROKE: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_STROKE; fill_base(display_channel, &display_channel->send_data.u.stroke.base, item, - sizeof(SpiceMsgDisplayDrawStroke), 0); + sizeof(SpiceMsgDisplayDrawStroke), drawable->surface_id); display_channel->send_data.u.stroke.data = drawable->u.stroke; fill_path(display_channel, &display_channel->send_data.u.stroke.data.path, item->group_id); fill_attr(display_channel, &display_channel->send_data.u.stroke.data.attr, item->group_id); @@ -6306,7 +6700,7 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp case QXL_DRAW_TEXT: channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_TEXT; fill_base(display_channel, &display_channel->send_data.u.text.base, item, - sizeof(SpiceMsgDisplayDrawText), 0); + sizeof(SpiceMsgDisplayDrawText), drawable->surface_id); display_channel->send_data.u.text.data = drawable->u.text; fill_brush(display_channel, &display_channel->send_data.u.text.data.fore_brush, item); fill_brush(display_channel, &display_channel->send_data.u.text.data.back_brush, item); @@ -6500,7 +6894,7 @@ static inline void display_begin_send_massage(DisplayChannel *channel, void *ite { FreeList *free_list = &channel->send_data.free_list; - if (free_list->res->count) { + if (0 && free_list->res->count) { int sync_count = 0; int sub_index; int i; @@ -6923,7 +7317,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item) channel->send_data.header.type = SPICE_MSG_DISPLAY_DRAW_COPY; add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.copy, sizeof(SpiceMsgDisplayDrawCopy), 0, 0); - display_channel->send_data.u.copy.base.surface_id = 0; + display_channel->send_data.u.copy.base.surface_id = item->surface_id; display_channel->send_data.u.copy.base.box.left = item->pos.x; display_channel->send_data.u.copy.base.box.top = item->pos.y; display_channel->send_data.u.copy.base.box.right = item->pos.x + bitmap.x; @@ -7172,8 +7566,6 @@ static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCrea add_buf(channel, BUF_TYPE_RAW, &display->send_data.u.surface_create, sizeof(SpiceMsgSurfaceCreate), 0, 0); - display->surface_client_created = TRUE; - red_begin_send_massage(channel, NULL); } @@ -7190,7 +7582,6 @@ static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_i add_buf(channel, BUF_TYPE_RAW, &display->send_data.u.surface_destroy, sizeof(SpiceMsgSurfaceDestroy), 0, 0); - display->surface_client_created = FALSE; red_begin_send_massage(channel, NULL); } @@ -7416,11 +7807,18 @@ static void __show_tree_call(TreeItem *item, void *data) void red_show_tree(RedWorker *worker) { + int x; + ShowTreeData show_tree_data; show_tree_data.worker = worker; show_tree_data.level = 0; show_tree_data.container = NULL; - current_tree_for_each(worker, __show_tree_call, &show_tree_data); + for (x = 0; x < NUM_SURFACES; ++x) { + if (worker->surfaces[x].context.canvas) { + current_tree_for_each(worker, &worker->surfaces[x].current, __show_tree_call, + &show_tree_data); + } + } } static inline int channel_is_connected(RedChannel *channel) @@ -7491,7 +7889,8 @@ static SpiceCanvas *create_cairo_context(RedWorker *worker, uint32_t width, uint if (surface == NULL) { red_error("create cairo surface failed"); } - canvas = canvas_create(surface, depth, &worker->image_cache.base, NULL, + canvas = canvas_create(surface, depth, &worker->image_cache.base, + &worker->image_surfaces, NULL, &worker->preload_group_virt_mapping); pixman_image_unref (surface); return canvas; @@ -7503,7 +7902,8 @@ static SpiceCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, ui SpiceCanvas *canvas; oglctx_make_current(ctx); - if (!(canvas = gl_canvas_create(width, height, depth, &worker->image_cache.base, NULL, + if (!(canvas = gl_canvas_create(width, height, depth, &worker->image_cache.base, + &worker->image_surfaces, NULL, &worker->preload_group_virt_mapping))) { return NULL; } @@ -7593,34 +7993,46 @@ static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t return create; } -static inline void red_create_surface_item(RedWorker *worker, RedSurface *surface) +static inline void __red_create_surface_item(RedWorker *worker, int surface_id, uint32_t flags) { + RedSurface *surface; SurfaceCreateItem *create; - if (!surface->context.canvas) { - return; - } - if (!worker->display_channel) { return; } - create = get_surface_create_item(0, surface->context.width, surface->context.height, - surface->context.depth, SPICE_SURFACE_FLAGS_PRIMARY); + surface = &worker->surfaces[surface_id]; + + create = get_surface_create_item(surface_id, surface->context.width, surface->context.height, + surface->context.depth, flags); + + worker->display_channel->surface_client_created[surface_id] = TRUE; + red_pipe_add(&worker->display_channel->base, &create->pipe_item); } -static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width, +static inline void red_create_surface_item(RedWorker *worker, int surface_id) +{ + if (is_primary_surface(worker, surface_id)) { + __red_create_surface_item(worker, surface_id, SPICE_SURFACE_FLAGS_PRIMARY); + } else { + __red_create_surface_item(worker, surface_id, 0); + } +} + +static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width, uint32_t height, int32_t stride, uint8_t depth, void *line_0) { uint32_t i; - RedSurface *surface = &worker->surface; - + RedSurface *surface = &worker->surfaces[surface_id]; if (stride >= 0) { PANIC("Untested path stride >= 0"); } + if (depth != 16 && depth != 32) { + PANIC("As for now support just 32/16 depth surfaces"); + } PANIC_ON(surface->context.canvas); - ASSERT(surface_id == 0); surface->context.canvas_draws_on_surface = FALSE; surface->context.width = width; @@ -7628,8 +8040,12 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uin surface->context.depth = depth; surface->context.stride = stride; surface->context.line_0 = line_0; + memset(line_0 + (int32_t)(stride * (height - 1)), 0, height*abs(stride)); + surface->release_info = NULL; + ring_init(&surface->current); + ring_init(&surface->current_list); + ring_init(&surface->depend_on_me); surface->refs = 1; - if (worker->renderer != RED_RENDERER_INVALID) { surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderer, width, height, stride, @@ -7637,7 +8053,8 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uin if (!surface->context.canvas) { PANIC("drawing canvas creating failed - can`t create same type canvas"); } - red_create_surface_item(worker, surface); + + red_create_surface_item(worker, surface_id); return; } @@ -7645,9 +8062,9 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uin surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderers[i], width, height, stride, surface->context.depth, line_0); - if (surface->context.canvas) { + if (surface->context.canvas) { //no need canvas check worker->renderer = worker->renderers[i]; - red_create_surface_item(worker, surface); + red_create_surface_item(worker, surface_id); return; } } @@ -7707,7 +8124,7 @@ static void push_new_primary_surface(RedWorker *worker) if ((display_channel = worker->display_channel)) { red_pipe_add_type(&display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE); if (!display_channel->base.migrate) { - red_create_surface_item(worker, &worker->surface); + red_create_surface_item(worker, 0); } display_channel_push(worker); } @@ -7758,10 +8175,10 @@ static void on_new_display_channel(RedWorker *worker) return; } display_channel->base.messages_window = 0; - if (worker->surface.context.canvas) { - red_current_flush(worker); + if (worker->surfaces[0].context.canvas) { + red_current_flush(worker, 0); push_new_primary_surface(worker); - red_add_screen_image(worker); + red_add_surface_image(worker, 0); if (channel_is_connected(&display_channel->base)) { red_pipe_add_verb(&display_channel->base, SPICE_MSG_DISPLAY_MARK); red_disply_start_streams(display_channel); @@ -8359,7 +8776,7 @@ static void on_new_cursor_channel(RedWorker *worker) channel->base.messages_window = 0; red_pipe_add_type(&channel->base, PIPE_ITEM_TYPE_SET_ACK); - if (worker->surface.context.canvas && !channel->base.migrate) { + if (worker->surfaces[0].context.canvas && !channel->base.migrate) { red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT); } } @@ -8551,12 +8968,17 @@ static void red_wait_outgoiong_item(RedChannel *channel) static inline void handle_dev_update(RedWorker *worker) { RedWorkeMessage message; + const SpiceRect *rect; + uint32_t *surface_id; - ASSERT(worker->surface.context.canvas && worker->running); + //ASSERT(worker->surfaces[0].context.canvas && worker->running); flush_display_commands(worker); - red_update_area(worker, worker->qxl->get_update_area(worker->qxl)); + worker->qxl->get_update_area(worker->qxl, &rect, &surface_id); + ASSERT(worker->running); + validate_surface(worker, *surface_id); + red_update_area(worker, rect, *surface_id); message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); } @@ -8596,12 +9018,14 @@ static inline void handle_dev_del_memslot(RedWorker *worker) worker->mem_slots[slot_group_id][slot_id].virt_end_addr = 0; } -static inline void destroy_surface_wait(RedWorker *worker) +static inline void destroy_surface_wait(RedWorker *worker, int surface_id) { - flush_display_commands(worker); + if (worker->surfaces[surface_id].context.canvas) { + red_handle_depends_on_target_surface(worker, surface_id); + } red_flush_surface_pipe(worker); red_display_clear_glz_drawables(worker->display_channel); - red_current_clear(worker); + red_current_clear(worker, surface_id); red_wait_outgoiong_item((RedChannel *)worker->display_channel); if (worker->display_channel) { ASSERT(!worker->display_channel->base.send_data.item); @@ -8617,8 +9041,9 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker) ASSERT(surface_id == 0); - if (worker->surface.context.canvas) { - destroy_surface_wait(worker); + flush_display_commands(worker); + if (worker->surfaces[0].context.canvas) { + destroy_surface_wait(worker, 0); } message = RED_WORKER_MESSAGE_READY; @@ -8627,10 +9052,22 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker) static inline void handle_dev_destroy_surfaces(RedWorker *worker) { + int i; RedWorkeMessage message; - destroy_surface_wait(worker); - __red_destroy_surface(worker); + flush_display_commands(worker); + //to handle better + if (worker->surfaces[0].context.canvas) { + destroy_surface_wait(worker, 0); + } + for (i = 0; i < NUM_SURFACES; ++i) { + if (worker->surfaces[i].context.canvas) { + destroy_surface_wait(worker, i); + if (worker->surfaces[i].context.canvas) { + __red_destroy_surface(worker, i); + } + } + } ASSERT(ring_is_empty(&worker->streams)); red_wait_outgoiong_item((RedChannel *)worker->cursor_channel); @@ -8650,7 +9087,10 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker) } } - ASSERT(!worker->surface.context.canvas); + //to handle better + for (i = 0; i < NUM_SURFACES; ++i) { + ASSERT(!worker->surfaces[i].context.canvas); + } worker->cursor_visible = TRUE; worker->cursor_position.x = worker->cursor_position.y = 0; @@ -8685,7 +9125,6 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker) line_0); if (worker->display_channel) { - red_create_surface_item(worker, &worker->surface); red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_MARK); display_channel_push(worker); } @@ -8721,12 +9160,12 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker) ASSERT(!worker->cursor_channel->base.send_data.item); } - - destroy_surface_wait(worker); - red_destroy_surface(worker); + flush_display_commands(worker); + destroy_surface_wait(worker, 0); + red_destroy_surface(worker, 0); ASSERT(ring_is_empty(&worker->streams)); - ASSERT(!worker->surface.context.canvas); + ASSERT(!worker->surfaces[surface_id].context.canvas); worker->cursor_visible = TRUE; worker->cursor_position.x = worker->cursor_position.y = 0; @@ -8845,17 +9284,23 @@ static void handle_dev_input(EventListener *listener, uint32_t events) case RED_WORKER_MESSAGE_LOAD: red_printf("load"); ASSERT(!worker->running); - red_add_screen_image(worker); + red_add_surface_image(worker, 0); red_cursor_load(worker); message = RED_WORKER_MESSAGE_READY; write_message(worker->channel, &message); break; - case RED_WORKER_MESSAGE_STOP: { + case RED_WORKER_MESSAGE_STOP: { + int x; + red_printf("stop"); ASSERT(worker->running); worker->running = FALSE; red_display_clear_glz_drawables(worker->display_channel); - red_current_flush(worker); + for (x = 0; x < NUM_SURFACES; ++x) { + if (worker->surfaces->context.canvas) { + red_current_flush(worker, x); + } + } red_cursor_flush(worker); red_wait_outgoiong_item((RedChannel *)worker->display_channel); red_wait_outgoiong_item((RedChannel *)worker->cursor_channel); @@ -8997,8 +9442,8 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data) worker->image_compression = init_data->image_compression; worker->streaming_video = init_data->streaming_video; ring_init(&worker->current_list); - ring_init(&worker->current); image_cache_init(&worker->image_cache); + image_surface_init(worker); drawables_init(worker); cursor_items_init(worker); red_init_streams(worker); @@ -9029,6 +9474,8 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data) worker->generation_bits = init_data->memslot_gen_bits; worker->mem_slot_bits = init_data->memslot_id_bits; worker->internal_groupslot_id = init_data->internal_groupslot_id; + PANIC_ON(init_data->n_surfaces > NUM_SURFACES); + worker->n_surfaces = init_data->n_surfaces; red_create_mem_slots(worker); worker->preload_group_virt_mapping.ops = &preload_group_virt_mapping_ops; diff --git a/server/red_worker.h b/server/red_worker.h index 141caee3..54577db4 100644 --- a/server/red_worker.h +++ b/server/red_worker.h @@ -96,6 +96,7 @@ typedef struct WorkerInitData { uint8_t memslot_gen_bits; uint8_t memslot_id_bits; uint8_t internal_groupslot_id; + uint32_t n_surfaces; } WorkerInitData; void *red_worker_main(void *arg); diff --git a/server/vd_interface.h b/server/vd_interface.h index 674fae00..6d76b9ec 100644 --- a/server/vd_interface.h +++ b/server/vd_interface.h @@ -153,6 +153,7 @@ typedef struct QXLDevInitInfo { uint8_t memslot_id_bits; uint32_t qxl_ram_size; uint8_t internal_groupslot_id; + uint32_t n_surfaces; } QXLDevInitInfo; struct QXLDevMemSlot { @@ -178,6 +179,8 @@ struct QXLDevSurfaceCreate { uint32_t group_id; }; +struct SpiceRect; + struct QXLInterface { VDInterface base; @@ -196,7 +199,7 @@ struct QXLInterface { void (*release_resource)(QXLInterface *qxl, struct QXLReleaseInfoExt release_info); int (*get_cursor_command)(QXLInterface *qxl, struct QXLCommandExt *cmd); int (*req_cursor_notification)(QXLInterface *qxl); - const struct SpiceRect *(*get_update_area)(QXLInterface *qxl); + void (*get_update_area)(QXLInterface *qxl, const struct SpiceRect **rect, uint32_t **surface_id); void (*notify_update)(QXLInterface *qxl, uint32_t update_id); void (*set_save_data)(QXLInterface *qxl, void *data, int size); void *(*get_save_data)(QXLInterface *qxl); |