[Spice-devel] [PATCH] spice server: surface create/destroy protocol support

Izik Eidus ieidus at redhat.com
Sat Feb 20 02:40:23 PST 2010


From 3d5ce2e630a02f5edd8b22fe353433bb9a8321d8 Mon Sep 17 00:00:00 2001
From: Izik Eidus <ieidus at redhat.com>
Date: Thu, 18 Feb 2010 01:11:33 +0200
Subject: [PATCH] spice server: surface create/destroy protocol support

Now we can send commands from the server to the client
to destroy surfaces (right now just the primary surface)

(Needed for offscreens support)

Another patch`s on the way.

Signed-off-by: Izik Eidus <ieidus at redhat.com>
---
 client/debug.h             |    5 +
 client/display_channel.cpp |  147 +++++++++++++++++++++--------
 client/display_channel.h   |    8 ++
 server/red_worker.c        |  224 +++++++++++++++++++++++++++++++++-----------
 4 files changed, 285 insertions(+), 99 deletions(-)

diff --git a/client/debug.h b/client/debug.h
index 1c6f6a4..ce8fc98 100644
--- a/client/debug.h
+++ b/client/debug.h
@@ -92,6 +92,11 @@ LOG4CPP_LOGGER("spice")
     ON_PANIC();                             \
 }
 
+#define PANIC_ON(x) if ((x)) {                      \
+    LOG(FATAL, "%s panic %s\n", __FUNCTION__, #x);  \
+    ON_PANIC();                                     \
+}
+
 #define DBGLEVEL 1000
 
 #define DBG(level, format, ...) {               \
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index a60832a..513ab7b 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -46,9 +46,9 @@
 
 static Mutex avcodec_mutex;
 
-class SetModeEvent: public SyncEvent {
+class CreatePrimarySurfaceEvent: public SyncEvent {
 public:
-    SetModeEvent(DisplayChannel& channel, int width, int height, int depth)
+   CreatePrimarySurfaceEvent(DisplayChannel& channel, int width, int height, int depth)
         : _channel (channel)
         , _width (width)
         , _height (height)
@@ -59,7 +59,6 @@ public:
     virtual void do_response(AbstractProcessLoop& events_loop)
     {
         Application* app = (Application*)events_loop.get_owner();
-        _channel.destroy_canvas();
         _channel.screen()->lock_size();
         _channel.screen()->resize(_width, _height);
         _channel.create_canvas(app->get_canvas_types(), _width, _height, _depth);
@@ -72,6 +71,22 @@ private:
     int _depth;
 };
 
+class DestroyPrimarySurfaceEvent: public SyncEvent {
+public:
+    DestroyPrimarySurfaceEvent(DisplayChannel& channel)
+        : _channel (channel)
+    {
+    }
+
+    virtual void do_response(AbstractProcessLoop& events_loop)
+    {
+        _channel.destroy_canvas();
+    }
+
+private:
+    DisplayChannel& _channel;
+};
+
 class UnlockScreenEvent: public Event {
 public:
     UnlockScreenEvent(RedScreen* screen)
@@ -664,7 +679,6 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
                          sizeof(SpiceMsgDisconnect));
     handler->set_handler(SPICE_MSG_NOTIFY, &DisplayChannel::handle_notify, sizeof(SpiceMsgNotify));
 
-    handler->set_handler(SPICE_MSG_DISPLAY_MODE, &DisplayChannel::handle_mode, sizeof(SpiceMsgDisplayMode));
     handler->set_handler(SPICE_MSG_DISPLAY_MARK, &DisplayChannel::handle_mark, 0);
     handler->set_handler(SPICE_MSG_DISPLAY_RESET, &DisplayChannel::handle_reset, 0);
 
@@ -688,6 +702,11 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
     handler->set_handler(SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL,
                          &DisplayChannel::handle_stream_destroy_all, 0);
 
+    handler->set_handler(SPICE_MSG_DISPLAY_SURFACE_CREATE, &DisplayChannel::handle_surface_create,
+                         sizeof(SpiceMsgSurfaceCreate));
+    handler->set_handler(SPICE_MSG_DISPLAY_SURFACE_DESTROY, &DisplayChannel::handle_surface_destroy,
+                         sizeof(SpiceMsgSurfaceDestroy));
+
     get_process_loop().add_trigger(_streams_trigger);
 #ifdef USE_OGL
     get_process_loop().add_trigger(_gl_interrupt_recreate);
@@ -1228,44 +1247,6 @@ void DisplayChannel::create_canvas(const std::vector<int>& canvas_types, int wid
     set_draw_handlers();
 }
 
-void DisplayChannel::handle_mode(RedPeer::InMessage* message)
-{
-    SpiceMsgDisplayMode *mode = (SpiceMsgDisplayMode *)message->data();
-
-    _mark = false;
-    attach_to_screen(get_client().get_application(), get_id());
-    clear_area();
-#ifdef USE_OGL
-    if (screen()) {
-        if (_canvas.get()) {
-            if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) {
-                screen()->unset_type_gl();
-                screen()->untouch_context();
-            }
-        }
-    }
-#endif
-    AutoRef<SetModeEvent> event(new SetModeEvent(*this, mode->x_res,
-                                                 mode->y_res, mode->bits));
-    get_client().push_event(*event);
-    (*event)->wait();
-    if (!(*event)->success()) {
-        THROW("set mode failed");
-    }
-
-    _x_res = mode->x_res;
-    _y_res = mode->y_res;
-    _depth = mode->bits;
-
-#ifdef USE_OGL
-    if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) {
-        ((GCanvas *)(_canvas.get()))->touch_context();
-        screen()->set_update_interrupt_trigger(&_interrupt_update);
-        screen()->set_type_gl();
-    }
-#endif
-}
-
 void DisplayChannel::handle_mark(RedPeer::InMessage *message)
 {
     _mark = true;
@@ -1367,6 +1348,7 @@ void DisplayChannel::handle_stream_create(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayStreamCreate* stream_create = (SpiceMsgDisplayStreamCreate*)message->data();
 
+    PANIC_ON(stream_create->surface_id != 0);
     Lock lock(_streams_lock);
     if (_streams.size() <= stream_create->id) {
         _streams.resize(stream_create->id + 1);
@@ -1465,6 +1447,74 @@ void DisplayChannel::handle_stream_destroy_all(RedPeer::InMessage* message)
     destroy_strams();
 }
 
+void DisplayChannel::create_primary_surface(int width, int height, int depth)
+{
+   _mark = false;
+    attach_to_screen(get_client().get_application(), get_id());
+    clear_area();
+
+    AutoRef<CreatePrimarySurfaceEvent> event(new CreatePrimarySurfaceEvent(*this, width, height,
+                                                                           depth));
+    get_client().push_event(*event);
+    (*event)->wait();
+    if (!(*event)->success()) {
+        THROW("Create primary surface failed");
+    }
+
+    _x_res = width;
+    _y_res = height;
+    _depth = depth;
+
+#ifdef USE_OGL
+    if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) {
+        ((GCanvas *)(_canvas.get()))->touch_context();
+        screen()->set_update_interrupt_trigger(&_interrupt_update);
+        screen()->set_type_gl();
+    }
+#endif
+}
+
+void DisplayChannel::destroy_primary_surface()
+{
+#ifdef USE_OGL
+    if (screen()) {
+        if (_canvas.get()) {
+            if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) {
+                screen()->unset_type_gl();
+                screen()->untouch_context();
+            }
+        }
+    }
+#endif
+
+    AutoRef<DestroyPrimarySurfaceEvent> event(new DestroyPrimarySurfaceEvent(*this));
+    get_client().push_event(*event);
+    (*event)->wait();
+    if (!(*event)->success()) {
+        THROW("Destroying primary surface failed");
+    }
+
+    AutoRef<UnlockScreenEvent> unlock_event(new UnlockScreenEvent(screen()));
+    get_client().push_event(*unlock_event);
+}
+
+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);
+}
+
+void DisplayChannel::handle_surface_destroy(RedPeer::InMessage* message)
+{
+    SpiceMsgSurfaceDestroy* surface_destroy = (SpiceMsgSurfaceDestroy*)message->data();
+    PANIC_ON(surface_destroy->surface_id != 0);
+
+    destroy_primary_surface();
+}
+
 #define PRE_DRAW
 #define POST_DRAW
 
@@ -1478,6 +1528,7 @@ void DisplayChannel::handle_stream_destroy_all(RedPeer::InMessage* message)
 void DisplayChannel::handle_copy_bits(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayCopyBits* copy_bits = (SpiceMsgDisplayCopyBits*)message->data();
+    PANIC_ON(copy_bits->base.surface_id != 0);
     PRE_DRAW;
     _canvas->copy_bits(*copy_bits, message->size());
     POST_DRAW;
@@ -1487,72 +1538,84 @@ void DisplayChannel::handle_copy_bits(RedPeer::InMessage* message)
 void DisplayChannel::handle_draw_fill(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawFill* fill = (SpiceMsgDisplayDrawFill*)message->data();
+    PANIC_ON(fill->base.surface_id != 0);
     DRAW(fill);
 }
 
 void DisplayChannel::handle_draw_opaque(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawOpaque* opaque = (SpiceMsgDisplayDrawOpaque*)message->data();
+    PANIC_ON(opaque->base.surface_id != 0);
     DRAW(opaque);
 }
 
 void DisplayChannel::handle_draw_copy(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawCopy* copy = (SpiceMsgDisplayDrawCopy*)message->data();
+    PANIC_ON(copy->base.surface_id != 0);
     DRAW(copy);
 }
 
 void DisplayChannel::handle_draw_blend(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawBlend* blend = (SpiceMsgDisplayDrawBlend*)message->data();
+    PANIC_ON(blend->base.surface_id != 0);
     DRAW(blend);
 }
 
 void DisplayChannel::handle_draw_blackness(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawBlackness* blackness = (SpiceMsgDisplayDrawBlackness*)message->data();
+    PANIC_ON(blackness->base.surface_id != 0);
     DRAW(blackness);
 }
 
 void DisplayChannel::handle_draw_whiteness(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawWhiteness* whiteness = (SpiceMsgDisplayDrawWhiteness*)message->data();
+    PANIC_ON(whiteness->base.surface_id != 0);
     DRAW(whiteness);
 }
 
 void DisplayChannel::handle_draw_invers(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawInvers* invers = (SpiceMsgDisplayDrawInvers*)message->data();
+    PANIC_ON(invers->base.surface_id != 0);
     DRAW(invers);
 }
 
 void DisplayChannel::handle_draw_rop3(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawRop3* rop3 = (SpiceMsgDisplayDrawRop3*)message->data();
+    PANIC_ON(rop3->base.surface_id != 0);
     DRAW(rop3);
 }
 
 void DisplayChannel::handle_draw_stroke(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawStroke* stroke = (SpiceMsgDisplayDrawStroke*)message->data();
+    PANIC_ON(stroke->base.surface_id != 0);
     DRAW(stroke);
 }
 
 void DisplayChannel::handle_draw_text(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawText* text = (SpiceMsgDisplayDrawText*)message->data();
+    PANIC_ON(text->base.surface_id != 0);
     DRAW(text);
 }
 
 void DisplayChannel::handle_draw_transparent(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawTransparent* transparent = (SpiceMsgDisplayDrawTransparent*)message->data();
+    PANIC_ON(transparent->base.surface_id != 0);
     DRAW(transparent);
 }
 
 void DisplayChannel::handle_draw_alpha_blend(RedPeer::InMessage* message)
 {
     SpiceMsgDisplayDrawAlphaBlend* alpha_blend = (SpiceMsgDisplayDrawAlphaBlend*)message->data();
+    PANIC_ON(alpha_blend->base.surface_id != 0);
     DRAW(alpha_blend);
 }
 
diff --git a/client/display_channel.h b/client/display_channel.h
index 802898f..b3157d9 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -132,6 +132,9 @@ private:
     void destroy_strams();
     void update_cursor();
 
+    void create_primary_surface(int width, int height, int depth);
+    void destroy_primary_surface();
+
     void handle_mode(RedPeer::InMessage* message);
     void handle_mark(RedPeer::InMessage* message);
     void handle_reset(RedPeer::InMessage* message);
@@ -147,6 +150,9 @@ private:
     void handle_stream_destroy(RedPeer::InMessage* message);
     void handle_stream_destroy_all(RedPeer::InMessage* message);
 
+    void handle_surface_create(RedPeer::InMessage* message);
+    void handle_surface_destroy(RedPeer::InMessage* message);
+
     void handle_draw_fill(RedPeer::InMessage* message);
     void handle_draw_opaque(RedPeer::InMessage* message);
     void handle_draw_copy(RedPeer::InMessage* message);
@@ -209,6 +215,8 @@ private:
     InterruptUpdate _interrupt_update;
 
     friend class SetModeEvent;
+    friend class CreatePrimarySurfaceEvent;
+    friend class DestroyPrimarySurfaceEvent;
     friend class ActivateTimerEvent;
     friend class VideoStream;
     friend class StreamsTrigger;
diff --git a/server/red_worker.c b/server/red_worker.c
index 2b50b9f..54f10dc 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -221,7 +221,6 @@ typedef struct BufDescriptor {
 
 enum {
     PIPE_ITEM_TYPE_DRAW,
-    PIPE_ITEM_TYPE_MODE,
     PIPE_ITEM_TYPE_INVAL_ONE,
     PIPE_ITEM_TYPE_CURSOR,
     PIPE_ITEM_TYPE_MIGRATE,
@@ -239,6 +238,8 @@ enum {
     PIPE_ITEM_TYPE_PIXMAP_RESET,
     PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE,
     PIPE_ITEM_TYPE_INVAL_PALLET_CACHE,
+    PIPE_ITEM_TYPE_CREATE_SURFACE,
+    PIPE_ITEM_TYPE_DESTROY_SURFACE,
 };
 
 typedef struct PipeItem {
@@ -279,6 +280,16 @@ struct CacheItem {
     uint32_t inval_type;
 };
 
+typedef struct SurfaceCreateItem {
+    SpiceMsgSurfaceCreate surface_create;
+    PipeItem pipe_item;
+} SurfaceCreateItem;
+
+typedef struct SurfaceDestroyItem {
+    SpiceMsgSurfaceDestroy surface_destroy;
+    PipeItem pipe_item;
+} SurfaceDestroyItem;
+
 enum {
     CURSOR_TYPE_INVALID,
     CURSOR_TYPE_DEV,
@@ -627,6 +638,8 @@ 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;
+
     struct {
         union {
             SpiceMsgDisplayDrawFill fill;
@@ -644,6 +657,8 @@ struct DisplayChannel {
             SpiceMsgDisplayDrawText text;
             SpiceMsgDisplayMode mode;
             SpiceMsgDisplayInvalOne inval_one;
+            SpiceMsgSurfaceCreate surface_create;
+            SpiceMsgSurfaceDestroy surface_destroy;
             WaitForChannels wait;
             struct {
                 SpiceMsgDisplayStreamCreate message;
@@ -878,10 +893,10 @@ typedef struct DrawContext {
     void *line_0;
 } DrawContext;
 
-typedef struct Surface {
+typedef struct RedSurface {
     uint32_t refs;
     DrawContext context;
-} Surface;
+} RedSurface;
 
 #ifdef STREAM_TRACE
 typedef struct ItemTrace {
@@ -928,7 +943,7 @@ typedef struct RedWorker {
     uint32_t renderer;
 
     DrawFuncs draw_funcs;
-    Surface surface;
+    RedSurface surface;
 
     Ring current_list;
     Ring current;
@@ -1452,7 +1467,6 @@ static void red_pipe_clear(RedChannel *channel)
         case PIPE_ITEM_TYPE_PIXMAP_RESET:
         case PIPE_ITEM_TYPE_PIXMAP_SYNC:
         case PIPE_ITEM_TYPE_INVAL_ONE:
-        case PIPE_ITEM_TYPE_MODE:
         case PIPE_ITEM_TYPE_MIGRATE:
         case PIPE_ITEM_TYPE_SET_ACK:
         case PIPE_ITEM_TYPE_CURSOR_INIT:
@@ -1460,6 +1474,8 @@ 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:
@@ -1533,9 +1549,36 @@ static void drawables_init(RedWorker *worker)
 
 static void red_reset_stream_trace(RedWorker *worker);
 
+static SurfaceDestroyItem *get_surface_destroy_item(uint32_t surface_id)
+{
+    SurfaceDestroyItem *destroy;
+
+    destroy = (SurfaceDestroyItem *)malloc(sizeof(SurfaceDestroyItem));
+    PANIC_ON(!destroy);
+
+    destroy->surface_destroy.surface_id = surface_id;
+
+    red_pipe_item_init(&destroy->pipe_item, PIPE_ITEM_TYPE_DESTROY_SURFACE);
+
+    return destroy;
+}
+
+static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_id)
+{
+    SurfaceDestroyItem *destroy;
+
+    if (!worker->display_channel) {
+        return;
+    }
+
+    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)
 {
-    Surface *surface = &worker->surface;
+    RedSurface *surface = &worker->surface;
 
     if (!--worker->surface.refs) {
 #ifdef STREAM_TRACE
@@ -1543,12 +1586,13 @@ static inline void __red_destroy_surface(RedWorker *worker)
 #endif
         worker->draw_funcs.destroy(surface->context.canvas);
         surface->context.canvas = NULL;
+        red_destroy_surface_item(worker, 0);
     }
 }
 
 static inline void red_destroy_surface(RedWorker *worker)
 {
-    Surface *surface = &worker->surface;
+    RedSurface *surface = &worker->surface;
 
     PANIC_ON(!surface->context.canvas);
     __red_destroy_surface(worker);
@@ -4777,10 +4821,11 @@ static inline void fill_rects_clip(RedChannel *channel, QXLPHYSICAL *in_clip, ui
 }
 
 static void fill_base(DisplayChannel *display_channel, SpiceMsgDisplayBase *base, Drawable *drawable,
-                      uint32_t size)
+                      uint32_t size, uint32_t surface_id)
 {
     RedChannel *channel = &display_channel->base;
     add_buf(channel, BUF_TYPE_RAW, base, size, 0, 0);
+    base->surface_id = surface_id;
     base->box = drawable->qxl_drawable->bbox;
     base->clip = drawable->qxl_drawable->clip;
 
@@ -6183,7 +6228,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));
+                  sizeof(SpiceMsgDisplayDrawFill), 0);
         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);
@@ -6191,7 +6236,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));
+                  sizeof(SpiceMsgDisplayDrawOpaque), 0);
         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);
@@ -6199,7 +6244,8 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         break;
     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));
+        fill_base(display_channel, &display_channel->send_data.u.copy.base, item,
+                  sizeof(SpiceMsgDisplayDrawCopy), 0);
         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);
@@ -6207,27 +6253,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));
+                  sizeof(SpiceMsgDisplayDrawTransparent), 0);
         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));
+                  sizeof(SpiceMsgDisplayDrawAlphaBlend), 0);
         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));
+                  sizeof(SpiceMsgDisplayCopyBits), 0);
         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));
+                  sizeof(SpiceMsgDisplayDrawBlend), 0);
         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);
@@ -6235,28 +6281,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));
+                  sizeof(SpiceMsgDisplayDrawBlackness), 0);
         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));
+                  sizeof(SpiceMsgDisplayDrawWhiteness), 0);
         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));
+                  sizeof(SpiceMsgDisplayDrawInvers), 0);
         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));
+                  sizeof(SpiceMsgDisplayDrawRop3), 0);
         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);
@@ -6265,7 +6311,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));
+                  sizeof(SpiceMsgDisplayDrawStroke), 0);
         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);
@@ -6273,7 +6319,8 @@ static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *disp
         break;
     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));
+        fill_base(display_channel, &display_channel->send_data.u.text.base, item,
+                  sizeof(SpiceMsgDisplayDrawText), 0);
         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);
@@ -6737,29 +6784,6 @@ static inline void send_qxl_drawable(DisplayChannel *display_channel, Drawable *
     red_send_qxl_drawable(display_channel->base.worker, display_channel, item);
 }
 
-static void red_send_mode(DisplayChannel *display_channel)
-{
-    RedChannel *channel;
-    RedWorker *worker;
-
-    ASSERT(display_channel);
-    worker = display_channel->base.worker;
-
-    if (!worker->surface.context.canvas) {
-        return;
-    }
-
-    channel = &display_channel->base;
-    channel->send_data.header.type = SPICE_MSG_DISPLAY_MODE;
-    display_channel->send_data.u.mode.x_res = worker->surface.context.width;
-    display_channel->send_data.u.mode.y_res = worker->surface.context.height;
-    display_channel->send_data.u.mode.bits = worker->surface.context.depth;
-
-    add_buf(channel, BUF_TYPE_RAW, &display_channel->send_data.u.mode, sizeof(SpiceMsgDisplayMode), 0, 0);
-
-    display_begin_send_massage(display_channel, NULL);
-}
-
 static void red_send_set_ack(RedChannel *channel)
 {
     ASSERT(channel);
@@ -6920,6 +6944,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.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;
@@ -6970,6 +6995,7 @@ static void red_display_send_upgrade(DisplayChannel *display_channel, UpgradeIte
     ASSERT(qxl_drawable->u.copy.mask.bitmap == 0);
 
     add_buf(channel, BUF_TYPE_RAW, copy, sizeof(SpiceMsgDisplayDrawCopy), 0, 0);
+    copy->base.surface_id = 0;
     copy->base.box = qxl_drawable->bbox;
     copy->base.clip.type = SPICE_CLIP_TYPE_RECTS;
     copy->base.clip.data = channel->send_data.header.size;
@@ -6990,6 +7016,7 @@ static void red_display_send_stream_start(DisplayChannel *display_channel, Strea
     ASSERT(stream);
     channel->send_data.header.type = SPICE_MSG_DISPLAY_STREAM_CREATE;
     SpiceMsgDisplayStreamCreate *stream_create = &display_channel->send_data.u.stream_create.message;
+    stream_create->surface_id = 0;
     stream_create->id = agent - display_channel->stream_agents;
     stream_create->flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
     stream_create->codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
@@ -7154,6 +7181,41 @@ static void red_send_cursor(CursorChannel *cursor_channel, CursorItem *cursor)
     red_release_cursor(channel->worker, cursor);
 }
 
+static void red_send_surface_create(DisplayChannel *display, SpiceMsgSurfaceCreate *surface_create)
+{
+    RedChannel *channel;
+
+    ASSERT(display);
+    channel = &display->base;
+
+    channel->send_data.header.type = SPICE_MSG_DISPLAY_SURFACE_CREATE;
+    display->send_data.u.surface_create = *surface_create;
+
+    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);
+}
+
+static void red_send_surface_destroy(DisplayChannel *display, uint32_t surface_id)
+{
+    RedChannel *channel;
+
+    ASSERT(display);
+    channel = &display->base;
+
+    channel->send_data.header.type = SPICE_MSG_DISPLAY_SURFACE_DESTROY;
+    display->send_data.u.surface_destroy.surface_id = surface_id;
+
+    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);
+}
+
 static inline PipeItem *red_pipe_get(RedChannel *channel)
 {
     PipeItem *item;
@@ -7217,10 +7279,6 @@ static void display_channel_push(RedWorker *worker)
             display_send_verb(display_channel, ((VerbItem*)pipe_item)->verb);
             free(pipe_item);
             break;
-        case PIPE_ITEM_TYPE_MODE:
-            red_send_mode(display_channel);
-            free(pipe_item);
-            break;
         case PIPE_ITEM_TYPE_MIGRATE:
             red_printf("PIPE_ITEM_TYPE_MIGRATE");
             display_channel_send_migrate(display_channel);
@@ -7251,6 +7309,20 @@ static void display_channel_push(RedWorker *worker)
             red_send_verb((RedChannel *)display_channel, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
             free(pipe_item);
             break;
+        case PIPE_ITEM_TYPE_CREATE_SURFACE: {
+            SurfaceCreateItem *surface_create = CONTAINEROF(pipe_item, SurfaceCreateItem,
+                                                            pipe_item);
+            red_send_surface_create(display_channel, &surface_create->surface_create);
+            free(surface_create);
+            break;
+        }
+        case PIPE_ITEM_TYPE_DESTROY_SURFACE: {
+            SurfaceDestroyItem *surface_destroy = CONTAINEROF(pipe_item, SurfaceDestroyItem,
+                                                              pipe_item);
+            red_send_surface_destroy(display_channel, surface_destroy->surface_destroy.surface_id);
+            free(surface_destroy);
+            break;
+        }
         default:
             red_error("invalid pipe item type");
         }
@@ -7617,7 +7689,7 @@ static inline void surface_init_draw_funcs(RedWorker *worker, uint32_t renderer)
     };
 }
 
-static inline void *create_canvas_for_surface(RedWorker *worker, Surface *surface,
+static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *surface,
                                               uint32_t renderer, uint32_t width, uint32_t height,
                                               int32_t stride, uint8_t depth, void *line_0)
 {
@@ -7641,16 +7713,52 @@ static inline void *create_canvas_for_surface(RedWorker *worker, Surface *surfac
     };
 }
 
-static inline void red_create_surface(RedWorker *worker, uint32_t width, uint32_t height,
-                                      int32_t stride, uint8_t depth, void *line_0)
+static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t width,
+                                                  uint32_t height, uint8_t depth, uint32_t flags)
+{
+    SurfaceCreateItem *create;
+
+    create = (SurfaceCreateItem *)malloc(sizeof(SurfaceCreateItem));
+    PANIC_ON(!create);
+
+    create->surface_create.surface_id = surface_id;
+    create->surface_create.width = width;
+    create->surface_create.height = height;
+    create->surface_create.flags = flags;
+
+    red_pipe_item_init(&create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
+
+    return create;
+}
+
+static inline void red_create_surface_item(RedWorker *worker, 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);
+    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,
+                                      uint32_t height, int32_t stride, uint8_t depth, void *line_0)
 {
     uint32_t i;
-    Surface *surface = &worker->surface;
+    RedSurface *surface = &worker->surface;
 
     if (stride >= 0) {
         PANIC("Untested path stride >= 0");
     }
     PANIC_ON(surface->context.canvas);
+    ASSERT(surface_id == 0);
 
     surface->context.width = width;
     surface->context.height = height;
@@ -7666,6 +7774,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t width, uint32_
         if (!surface->context.canvas) {
             PANIC("drawing canvas creating failed - can`t create same type canvas");
         }
+        red_create_surface_item(worker, surface);
         return;
     }
 
@@ -7676,6 +7785,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t width, uint32_
         if (surface->context.canvas) {
             worker->renderer = worker->renderers[i];
             surface_init_draw_funcs(worker, worker->renderers[i]);
+            red_create_surface_item(worker, surface);
             return;
         }
     }
@@ -7728,14 +7838,14 @@ static inline void red_flush_surface_pipe(RedWorker *worker)
     }
 }
 
-static void push_new_mode(RedWorker *worker)
+static void push_new_primary_surface(RedWorker *worker)
 {
     DisplayChannel *display_channel;
 
     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_pipe_add_type(&display_channel->base, PIPE_ITEM_TYPE_MODE);
+            red_create_surface_item(worker, &worker->surface);
         }
         display_channel_push(worker);
     }
@@ -7788,7 +7898,7 @@ static void on_new_display_channel(RedWorker *worker)
     display_channel->base.messages_window = 0;
     if (worker->surface.context.canvas) {
         red_current_flush(worker);
-        push_new_mode(worker);
+        push_new_primary_surface(worker);
         red_add_screen_image(worker);
         if (channel_is_connected(&display_channel->base)) {
             red_pipe_add_verb(&display_channel->base, SPICE_MSG_DISPLAY_MARK);
@@ -8730,11 +8840,11 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
         line_0 -= (int32_t)(surface.stride * (surface.height -1));
     }
 
-    red_create_surface(worker, surface.width, surface.height, surface.stride, surface.depth,
+    red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.depth,
                        line_0);
 
     if (worker->display_channel) {
-        red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_MODE);
+        red_create_surface_item(worker, &worker->surface);
         red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_MARK);
         display_channel_push(worker);
     }
-- 
1.6.6.1



More information about the Spice-devel mailing list