summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/canvas.cpp5
-rw-r--r--client/canvas.h143
-rw-r--r--client/display_channel.cpp342
-rw-r--r--client/display_channel.h31
-rw-r--r--client/red_cairo_canvas.cpp5
-rw-r--r--client/red_cairo_canvas.h2
-rw-r--r--client/red_gdi_canvas.cpp6
-rw-r--r--client/red_gdi_canvas.h2
-rw-r--r--client/red_gl_canvas.cpp5
-rw-r--r--client/red_gl_canvas.h2
-rw-r--r--common/cairo_canvas.c402
-rw-r--r--common/cairo_canvas.h1
-rw-r--r--common/canvas_base.c530
-rw-r--r--common/canvas_base.h76
-rw-r--r--common/gdi_canvas.c465
-rw-r--r--common/gdi_canvas.h1
-rw-r--r--common/gl_canvas.c2
-rw-r--r--common/gl_canvas.h1
-rw-r--r--server/red_dispatcher.c1
-rw-r--r--server/red_worker.c749
-rw-r--r--server/red_worker.h1
-rw-r--r--server/vd_interface.h5
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, &copy->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, &copy->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, &copy->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, &copy->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, &copy->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, &copy->mask);
+ set_scale_mode(canvas, copy->scale_mode);
+ set_clip(canvas, clip);
+ gdi_draw_bitmap_redrop(canvas->dc, &copy->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, &copy->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, &copy->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, &copy->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, &copy->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);