[Spice-devel] [RFC] spice with off screen support
Izik Eidus
ieidus at redhat.com
Tue Mar 30 16:03:25 PDT 2010
Ok, still need some clean ups and to go the code with meld
(For example i got there goto and stuff like that that i can remove)
But windows 7 look and feel better/faster than ever :-)
So what is missing is really only gdi support (trivial and will send it with gdi tomorrow)
Another things to note are:
There is alot of room for optimizations and improvments
some stuff to note that i want in this patch but decide not
to sending it in the current patch - as this patch is already too
big and complex, so i will send them later after this patch:
* background sending of off-screens commands
(give higher priority into the primary surface commands)
* much less brutal destruction of surfaces - right now
I am syncing everything into the client at the
~primary surface~ destruction (Only the primary surface
every other surfaces don`t have this issue)
* Protect surfaces that in the pipe against immidate data changes
before they are sent into the client (just matter of copy their data,
trivial)
(I guess i should have included this in this patch as it matter
of corectness, so will probably add it tommorow)
* another release ring? I dont sure anymore, started to implmented
and came into few questions....
* gl stuff - this going to be fun, but first i need to change
the current gl implemantion in the driver and instead of targeting
nvidia closed driver to target the latest kms stuff
commit 2d5442c0849ab9c99e7f613f659d406af4bc23fd
Author: Izik Eidus <ieidus at redhat.com>
Date: Wed Mar 31 01:43:27 2010 +0300
libspice: add off screens support
Signed-off-by: Izik Eidus <ieidus at redhat.com>
diff --git a/client/canvas.cpp b/client/canvas.cpp
index ba446c9..b72aad5 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 8e3a8f1..1e251ed 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 49e9457..397c724 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)
@@ -637,6 +680,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)
@@ -648,7 +727,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)
@@ -710,6 +788,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()
@@ -718,7 +798,7 @@ DisplayChannel::~DisplayChannel()
screen()->set_update_interrupt_trigger(NULL);
}
- destroy_canvas();
+ //destroy_canvas(); fixme destroy all
destroy_strams();
}
@@ -790,33 +870,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();
}
@@ -951,21 +1038,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
}
@@ -979,7 +1070,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
@@ -990,11 +1081,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 {
@@ -1099,8 +1194,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()) {
@@ -1120,12 +1218,14 @@ 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());
+ surfaces_mngr.add_canvas(surface_id, canvas);
+ surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas());
LOG_INFO("display %d: using cairo", get_id());
} catch (...) {
return false;
@@ -1134,27 +1234,25 @@ 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());
} catch (...) {
@@ -1166,13 +1264,14 @@ 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());
+ surfaces_mngr.add_canvas(surface_id, canvas);
+ surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas());
LOG_INFO("display %d: using gdi", get_id());
} catch (...) {
return false;
@@ -1182,21 +1281,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
@@ -1204,8 +1311,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;
@@ -1216,23 +1321,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
@@ -1241,8 +1346,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)
@@ -1262,8 +1365,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()));
@@ -1345,8 +1450,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);
@@ -1361,7 +1466,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,
@@ -1447,6 +1552,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();
@@ -1463,21 +1569,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();
}
@@ -1493,21 +1625,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
@@ -1515,102 +1661,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 d603a26..ac97bad 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);
#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 02c105a..71621d1 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 51c6c5a..ce76fef 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 9f38dfb..76e1542 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)
{
}
@@ -84,6 +84,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 83fc120..b0a2158 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 c6bb113..f9c4256 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 983f772..4a9f5a9 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 770ca4f..17a40a4 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 3f6fbbc..e65b407 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 e13a005..e15a971 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -190,6 +190,8 @@ typedef struct CanvasBase {
HDC dc;
#endif
+ SpiceImageSurfaces *surfaces;
+
LzData lz_data;
GlzData glz_data;
@@ -948,6 +950,34 @@ static void dump_surface(pixman_image_t *surface, int cache)
#endif
+static SpiceCanvas *canvas_get_surface_internal(CanvasBase *canvas, SPICE_ADDRESS addr)
+{
+ SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
+ access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
+
+ if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) {
+ SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor;
+ access_test(canvas, descriptor, sizeof(SpiceSurfaceImage));
+ return canvas->surfaces->ops->get(canvas->surfaces, surface->surface.surface_id);
+ }
+ return NULL;
+}
+
+static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_ADDRESS addr)
+{
+ SpiceImageDescriptor *descriptor;
+
+ descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
+ access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
+
+ if (descriptor->type == SPICE_IMAGE_TYPE_SURFACE) {
+ SpiceSurfaceImage *surface = (SpiceSurfaceImage *)descriptor;
+ access_test(canvas, descriptor, sizeof(SpiceSurfaceImage));
+ return canvas->surfaces->ops->get(canvas->surfaces, surface->surface.surface_id);
+ }
+ return NULL;
+}
+
#if defined(CAIRO_CANVAS_CACHE) || defined(CAIRO_CANVAS_IMAGE_CACHE)
//#define DEBUG_LZ
@@ -1065,6 +1095,16 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
#endif
+static SpiceCanvas *canvas_get_surface_mask(CanvasBase *canvas, SPICE_ADDRESS addr)
+{
+ return canvas_get_surface_mask_internal(canvas, addr);
+}
+
+static SpiceCanvas *canvas_get_surface(CanvasBase *canvas, SPICE_ADDRESS addr)
+{
+ return canvas_get_surface_internal(canvas, addr);
+}
+
static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
{
return canvas_get_image_internal(canvas, addr, TRUE);
@@ -1318,10 +1358,6 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int
*needs_invert_out = 0;
}
- if (!mask->bitmap) {
- return NULL;
- }
-
descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(mask->bitmap);
access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
need_invers = mask->flags & SPICE_MASK_FLAGS_INVERS;
@@ -1807,6 +1843,7 @@ static void canvas_mask_pixman(CanvasBase *canvas,
pixman_region32_t *dest_region,
SpiceQMask *mask, int x, int y)
{
+ SpiceCanvas *surface_canvas;
pixman_image_t *image, *subimage;
int needs_invert;
pixman_region32_t mask_region;
@@ -1815,13 +1852,19 @@ static void canvas_mask_pixman(CanvasBase *canvas,
int mask_width, mask_height, mask_stride;
pixman_box32_t extents;
- needs_invert = FALSE;
- image = canvas_get_mask(canvas,
- mask,
- &needs_invert);
+ if (!mask->bitmap) {
+ return;
+ }
- if (image == NULL) {
- return; /* no mask */
+ surface_canvas = canvas_get_surface_mask(canvas, mask->bitmap);
+ if (surface_canvas) {
+ needs_invert = mask->flags & SPICE_MASK_FLAGS_INVERS;
+ image = surface_canvas->ops->get_image(surface_canvas);
+ } else {
+ needs_invert = FALSE;
+ image = canvas_get_mask(canvas,
+ mask,
+ &needs_invert);
}
mask_data = pixman_image_get_data(image);
@@ -1921,20 +1964,35 @@ static void draw_brush(SpiceCanvas *canvas,
canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, color, rop);
}
break;
- case SPICE_BRUSH_TYPE_PATTERN:
+ case SPICE_BRUSH_TYPE_PATTERN: {
+ SpiceCanvas *surface_canvas;
+
pattern = &brush->u.pattern;
- tile = canvas_get_image(canvas_base, pattern->pat);
offset_x = pattern->pos.x;
offset_y = pattern->pos.y;
- if (rop == SPICE_ROP_COPY) {
- canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y);
+ surface_canvas = canvas_get_surface(canvas_base, pattern->pat);
+ if (surface_canvas) {
+ if (rop == SPICE_ROP_COPY) {
+ canvas->ops->fill_tiled_rects_from_surface(canvas, rects, n_rects, surface_canvas,
+ offset_x, offset_y);
+ } else {
+ canvas->ops->fill_tiled_rects_rop_from_surface(canvas, rects, n_rects,
+ surface_canvas, offset_x, offset_y,
+ rop);
+ }
} else {
- canvas->ops->fill_tiled_rects_rop(canvas, rects, n_rects,
- tile, offset_x, offset_y, rop);
+ tile = canvas_get_image(canvas_base, pattern->pat);
+ if (rop == SPICE_ROP_COPY) {
+ canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y);
+ } else {
+ canvas->ops->fill_tiled_rects_rop(canvas, rects, n_rects,
+ tile, offset_x, offset_y, rop);
+ }
+ pixman_image_unref(tile);
}
- pixman_image_unref(tile);
break;
+ }
case SPICE_BRUSH_TYPE_NONE:
/* Still need to do *something* here, because rop could be e.g invert dest */
canvas->ops->fill_solid_rects_rop(canvas, rects, n_rects, 0, rop);
@@ -1991,6 +2049,7 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
{
CanvasBase *canvas = (CanvasBase *)spice_canvas;
pixman_region32_t dest_region;
+ SpiceCanvas *surface_canvas;
pixman_image_t *src_image;
SpiceROP rop;
@@ -2013,36 +2072,67 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
return;
}
- src_image = canvas_get_image(canvas, copy->src_bitmap);
-
- if (rect_is_same_size(bbox, ©->src_area)) {
- if (rop == SPICE_ROP_COPY) {
- spice_canvas->ops->blit_image(spice_canvas, &dest_region,
- src_image,
- bbox->left - copy->src_area.left,
- bbox->top - copy->src_area.top);
+ surface_canvas = canvas_get_surface(canvas, copy->src_bitmap);
+ if (surface_canvas) {
+ if (rect_is_same_size(bbox, ©->src_area)) {
+ if (rop == SPICE_ROP_COPY) {
+ spice_canvas->ops->blit_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ bbox->left - copy->src_area.left,
+ bbox->top - copy->src_area.top);
+ } else {
+ spice_canvas->ops->blit_image_rop_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ bbox->left - copy->src_area.left,
+ bbox->top - copy->src_area.top,
+ rop);
+ }
} else {
- spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region,
- src_image,
- bbox->left - copy->src_area.left,
- bbox->top - copy->src_area.top,
- rop);
+ if (rop == SPICE_ROP_COPY) {
+ spice_canvas->ops->scale_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ copy->src_area.left,
+ copy->src_area.top,
+ copy->src_area.right - copy->src_area.left,
+ copy->src_area.bottom - copy->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ copy->scale_mode);
+ } else {
+ spice_canvas->ops->scale_image_rop_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ copy->src_area.left,
+ copy->src_area.top,
+ copy->src_area.right - copy->src_area.left,
+ copy->src_area.bottom - copy->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ copy->scale_mode,
+ rop);
+ }
}
} else {
- if (rop == SPICE_ROP_COPY) {
- spice_canvas->ops->scale_image(spice_canvas, &dest_region,
- src_image,
- copy->src_area.left,
- copy->src_area.top,
- copy->src_area.right - copy->src_area.left,
- copy->src_area.bottom - copy->src_area.top,
- bbox->left,
- bbox->top,
- bbox->right - bbox->left,
- bbox->bottom - bbox->top,
- copy->scale_mode);
+ src_image = canvas_get_image(canvas, copy->src_bitmap);
+ if (rect_is_same_size(bbox, ©->src_area)) {
+ if (rop == SPICE_ROP_COPY) {
+ spice_canvas->ops->blit_image(spice_canvas, &dest_region,
+ src_image,
+ bbox->left - copy->src_area.left,
+ bbox->top - copy->src_area.top);
+ } else {
+ spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region,
+ src_image,
+ bbox->left - copy->src_area.left,
+ bbox->top - copy->src_area.top,
+ rop);
+ }
} else {
- spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region,
+ if (rop == SPICE_ROP_COPY) {
+ spice_canvas->ops->scale_image(spice_canvas, &dest_region,
src_image,
copy->src_area.left,
copy->src_area.top,
@@ -2052,18 +2142,31 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
bbox->top,
bbox->right - bbox->left,
bbox->bottom - bbox->top,
- copy->scale_mode,
- rop);
+ copy->scale_mode);
+ } else {
+ spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region,
+ src_image,
+ copy->src_area.left,
+ copy->src_area.top,
+ copy->src_area.right - copy->src_area.left,
+ copy->src_area.bottom - copy->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ copy->scale_mode,
+ rop);
+ }
}
+ pixman_image_unref(src_image);
}
-
- pixman_image_unref(src_image);
pixman_region32_fini(&dest_region);
}
static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent)
{
CanvasBase *canvas = (CanvasBase *)spice_canvas;
+ SpiceCanvas *surface_canvas;
pixman_image_t *src_image;
pixman_region32_t dest_region;
@@ -2080,29 +2183,50 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
return;
}
- src_image = canvas_get_image(canvas, transparent->src_bitmap);
-
- if (rect_is_same_size(bbox, &transparent->src_area)) {
- spice_canvas->ops->colorkey_image(spice_canvas, &dest_region,
- src_image,
- bbox->left - transparent->src_area.left,
- bbox->top - transparent->src_area.top,
- transparent->true_color);
+ surface_canvas = canvas_get_surface(canvas, transparent->src_bitmap);
+ if (surface_canvas) {
+ if (rect_is_same_size(bbox, &transparent->src_area)) {
+ spice_canvas->ops->colorkey_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ bbox->left - transparent->src_area.left,
+ bbox->top - transparent->src_area.top,
+ transparent->true_color);
+ } else {
+ spice_canvas->ops->colorkey_scale_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ transparent->src_area.left,
+ transparent->src_area.top,
+ transparent->src_area.right - transparent->src_area.left,
+ transparent->src_area.bottom - transparent->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ transparent->true_color);
+ }
} else {
- spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region,
- src_image,
- transparent->src_area.left,
- transparent->src_area.top,
- transparent->src_area.right - transparent->src_area.left,
- transparent->src_area.bottom - transparent->src_area.top,
- bbox->left,
- bbox->top,
- bbox->right - bbox->left,
- bbox->bottom - bbox->top,
- transparent->true_color);
+ src_image = canvas_get_image(canvas, transparent->src_bitmap);
+ if (rect_is_same_size(bbox, &transparent->src_area)) {
+ spice_canvas->ops->colorkey_image(spice_canvas, &dest_region,
+ src_image,
+ bbox->left - transparent->src_area.left,
+ bbox->top - transparent->src_area.top,
+ transparent->true_color);
+ } else {
+ spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region,
+ src_image,
+ transparent->src_area.left,
+ transparent->src_area.top,
+ transparent->src_area.right - transparent->src_area.left,
+ transparent->src_area.bottom - transparent->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ transparent->true_color);
+ }
+ pixman_image_unref(src_image);
}
-
- pixman_image_unref(src_image);
pixman_region32_fini(&dest_region);
}
@@ -2110,6 +2234,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
{
CanvasBase *canvas = (CanvasBase *)spice_canvas;
pixman_region32_t dest_region;
+ SpiceCanvas *surface_canvas;
pixman_image_t *src_image;
pixman_region32_init_rect(&dest_region,
@@ -2126,34 +2251,62 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
return;
}
- src_image = canvas_get_image(canvas, alpha_blend->src_bitmap);
-
- if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
- spice_canvas->ops->blend_image(spice_canvas, &dest_region,
- src_image,
- alpha_blend->src_area.left,
- alpha_blend->src_area.top,
- bbox->left,
- bbox->top,
- bbox->right - bbox->left,
- bbox->bottom - bbox->top,
- alpha_blend->alpha);
- } else {
- spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region,
- src_image,
- alpha_blend->src_area.left,
- alpha_blend->src_area.top,
- alpha_blend->src_area.right - alpha_blend->src_area.left,
- alpha_blend->src_area.bottom - alpha_blend->src_area.top,
- bbox->left,
- bbox->top,
- bbox->right - bbox->left,
- bbox->bottom - bbox->top,
- SPICE_IMAGE_SCALE_MODE_NEAREST,
- alpha_blend->alpha);
+ surface_canvas = canvas_get_surface(canvas, alpha_blend->src_bitmap);
+ if (surface_canvas) {
+ if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
+ spice_canvas->ops->blend_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ alpha_blend->src_area.left,
+ alpha_blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ alpha_blend->alpha);
+ } else {
+ spice_canvas->ops->blend_scale_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ alpha_blend->src_area.left,
+ alpha_blend->src_area.top,
+ alpha_blend->src_area.right - alpha_blend->src_area.left,
+ alpha_blend->src_area.bottom - alpha_blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ SPICE_IMAGE_SCALE_MODE_NEAREST,
+ alpha_blend->alpha);
+ }
+ } else {
+ src_image = canvas_get_image(canvas, alpha_blend->src_bitmap);
+ if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
+ spice_canvas->ops->blend_image(spice_canvas, &dest_region,
+ src_image,
+ alpha_blend->src_area.left,
+ alpha_blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ alpha_blend->alpha);
+ } else {
+ spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region,
+ src_image,
+ alpha_blend->src_area.left,
+ alpha_blend->src_area.top,
+ alpha_blend->src_area.right - alpha_blend->src_area.left,
+ alpha_blend->src_area.bottom - alpha_blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ SPICE_IMAGE_SCALE_MODE_NEAREST,
+ alpha_blend->alpha);
+ }
+
+ pixman_image_unref(src_image);
}
- pixman_image_unref(src_image);
pixman_region32_fini(&dest_region);
}
@@ -2214,6 +2367,7 @@ static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spice
static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
{
CanvasBase *canvas = (CanvasBase *)spice_canvas;
+ SpiceCanvas *surface_canvas;
pixman_image_t *src_image;
pixman_region32_t dest_region;
SpiceROP rop;
@@ -2237,40 +2391,74 @@ static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceC
return;
}
- src_image = canvas_get_image(canvas, blend->src_bitmap);
-
- if (rect_is_same_size(bbox, &blend->src_area)) {
- if (rop == SPICE_ROP_COPY)
- spice_canvas->ops->blit_image(spice_canvas, &dest_region,
- src_image,
- bbox->left - blend->src_area.left,
- bbox->top - blend->src_area.top);
- else
- spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region,
+ surface_canvas = canvas_get_surface(canvas, blend->src_bitmap);
+ if (surface_canvas) {
+ if (rect_is_same_size(bbox, &blend->src_area)) {
+ if (rop == SPICE_ROP_COPY)
+ spice_canvas->ops->blit_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ bbox->left - blend->src_area.left,
+ bbox->top - blend->src_area.top);
+ else
+ spice_canvas->ops->blit_image_rop_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ bbox->left - blend->src_area.left,
+ bbox->top - blend->src_area.top,
+ rop);
+ } else {
+ double sx, sy;
+
+ sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left);
+ sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top);
+
+ if (rop == SPICE_ROP_COPY) {
+ spice_canvas->ops->scale_image_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ blend->src_area.left,
+ blend->src_area.top,
+ blend->src_area.right - blend->src_area.left,
+ blend->src_area.bottom - blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ blend->scale_mode);
+ } else {
+ spice_canvas->ops->scale_image_rop_from_surface(spice_canvas, &dest_region,
+ surface_canvas,
+ blend->src_area.left,
+ blend->src_area.top,
+ blend->src_area.right - blend->src_area.left,
+ blend->src_area.bottom - blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ blend->scale_mode, rop);
+ }
+ }
+ } else {
+ src_image = canvas_get_image(canvas, blend->src_bitmap);
+ if (rect_is_same_size(bbox, &blend->src_area)) {
+ if (rop == SPICE_ROP_COPY)
+ spice_canvas->ops->blit_image(spice_canvas, &dest_region,
src_image,
bbox->left - blend->src_area.left,
- bbox->top - blend->src_area.top,
- rop);
- } else {
- double sx, sy;
-
- sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left);
- sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top);
-
- if (rop == SPICE_ROP_COPY) {
- spice_canvas->ops->scale_image(spice_canvas, &dest_region,
- src_image,
- blend->src_area.left,
- blend->src_area.top,
- blend->src_area.right - blend->src_area.left,
- blend->src_area.bottom - blend->src_area.top,
- bbox->left,
- bbox->top,
- bbox->right - bbox->left,
- bbox->bottom - bbox->top,
- blend->scale_mode);
+ bbox->top - blend->src_area.top);
+ else
+ spice_canvas->ops->blit_image_rop(spice_canvas, &dest_region,
+ src_image,
+ bbox->left - blend->src_area.left,
+ bbox->top - blend->src_area.top,
+ rop);
} else {
- spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region,
+ double sx, sy;
+
+ sx = (double)(blend->src_area.right - blend->src_area.left) / (bbox->right - bbox->left);
+ sy = (double)(blend->src_area.bottom - blend->src_area.top) / (bbox->bottom - bbox->top);
+
+ if (rop == SPICE_ROP_COPY) {
+ spice_canvas->ops->scale_image(spice_canvas, &dest_region,
src_image,
blend->src_area.left,
blend->src_area.top,
@@ -2280,11 +2468,23 @@ static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceC
bbox->top,
bbox->right - bbox->left,
bbox->bottom - bbox->top,
- blend->scale_mode, rop);
+ blend->scale_mode);
+ } else {
+ spice_canvas->ops->scale_image_rop(spice_canvas, &dest_region,
+ src_image,
+ blend->src_area.left,
+ blend->src_area.top,
+ blend->src_area.right - blend->src_area.left,
+ blend->src_area.bottom - blend->src_area.top,
+ bbox->left,
+ bbox->top,
+ bbox->right - bbox->left,
+ bbox->bottom - bbox->top,
+ blend->scale_mode, rop);
+ }
}
+ pixman_image_unref(src_image);
}
-
- pixman_image_unref(src_image);
pixman_region32_fini(&dest_region);
}
@@ -2382,7 +2582,11 @@ typedef struct {
SpiceROP back_rop;
int solid;
uint32_t color;
- pixman_image_t *tile;
+ int use_surface_canvas;
+ union {
+ SpiceCanvas *surface_canvas;
+ pixman_image_t *tile;
+ };
int tile_offset_x;
int tile_offset_y;
} StrokeGC;
@@ -2505,16 +2709,31 @@ static void stroke_fill_rects(lineGC * pGC,
}
} else {
if (rop == SPICE_ROP_COPY) {
- canvas->ops->fill_tiled_rects(canvas, area_rects, n_area_rects,
- strokeGC->tile,
- strokeGC->tile_offset_x,
- strokeGC->tile_offset_y);
- } else {
- canvas->ops->fill_tiled_rects_rop(canvas, area_rects, n_area_rects,
+ if (strokeGC->use_surface_canvas) {
+ canvas->ops->fill_tiled_rects_from_surface(canvas, area_rects, n_area_rects,
+ strokeGC->surface_canvas,
+ strokeGC->tile_offset_x,
+ strokeGC->tile_offset_y);
+ } else {
+ canvas->ops->fill_tiled_rects(canvas, area_rects, n_area_rects,
strokeGC->tile,
strokeGC->tile_offset_x,
- strokeGC->tile_offset_y,
- rop);
+ strokeGC->tile_offset_y);
+ }
+ } else {
+ if (strokeGC->use_surface_canvas) {
+ canvas->ops->fill_tiled_rects_rop_from_surface(canvas, area_rects, n_area_rects,
+ strokeGC->surface_canvas,
+ strokeGC->tile_offset_x,
+ strokeGC->tile_offset_y,
+ rop);
+ } else {
+ canvas->ops->fill_tiled_rects_rop(canvas, area_rects, n_area_rects,
+ strokeGC->tile,
+ strokeGC->tile_offset_x,
+ strokeGC->tile_offset_y,
+ rop);
+ }
}
}
@@ -2661,6 +2880,7 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
SpiceClip *clip, SpiceStroke *stroke)
{
CanvasBase *canvas = (CanvasBase *)spice_canvas;
+ SpiceCanvas *surface_canvas = NULL;
StrokeGC gc = { { 0 } };
lineGCOps ops = {
stroke_fill_spans,
@@ -2754,8 +2974,16 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
break;
case SPICE_BRUSH_TYPE_PATTERN:
gc.solid = FALSE;
- gc.tile = canvas_get_image(canvas,
- stroke->brush.u.pattern.pat);
+ surface_canvas = canvas_get_surface(canvas,
+ stroke->brush.u.pattern.pat);
+ if (surface_canvas) {
+ gc.use_surface_canvas = TRUE;
+ gc.surface_canvas = surface_canvas;
+ } else {
+ gc.use_surface_canvas = FALSE;
+ gc.tile = canvas_get_image(canvas,
+ stroke->brush.u.pattern.pat);
+ }
gc.tile_offset_x = stroke->brush.u.pattern.pos.x;
gc.tile_offset_y = stroke->brush.u.pattern.pos.y;
break;
@@ -2817,17 +3045,20 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
}
stroke_lines_free(&lines);
- if (!gc.solid && gc.tile) {
+ if (!gc.solid && gc.tile && !surface_canvas) {
pixman_image_unref(gc.tile);
}
pixman_region32_fini(&gc.dest_region);
}
+
+//need surfaces handling here !!!
static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
SpiceClip *clip, SpiceRop3 *rop3)
{
CanvasBase *canvas = (CanvasBase *)spice_canvas;
+ SpiceCanvas *surface_canvas;
pixman_region32_t dest_region;
pixman_image_t *d;
pixman_image_t *s;
@@ -2848,7 +3079,12 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
heigth = bbox->bottom - bbox->top;
d = canvas_get_image_from_self(spice_canvas, bbox->left, bbox->top, width, heigth);
- s = canvas_get_image(canvas, rop3->src_bitmap);
+ surface_canvas = canvas_get_surface(canvas, rop3->src_bitmap);
+ if (surface_canvas) {
+ s = surface_canvas->ops->get_image(surface_canvas);
+ } else {
+ s = canvas_get_image(canvas, rop3->src_bitmap);
+ }
if (!rect_is_same_size(bbox, &rop3->src_area)) {
pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, width, heigth,
@@ -2866,7 +3102,15 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
CANVAS_ERROR("bad src bitmap size");
}
if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
- pixman_image_t *p = canvas_get_image(canvas, rop3->brush.u.pattern.pat);
+ SpiceCanvas *_surface_canvas;
+ pixman_image_t *p;
+
+ _surface_canvas = canvas_get_surface(canvas, rop3->brush.u.pattern.pat);
+ if (_surface_canvas) {
+ p = _surface_canvas->ops->get_image(_surface_canvas);
+ } else {
+ p = canvas_get_image(canvas, rop3->brush.u.pattern.pat);
+ }
SpicePoint pat_pos;
pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
@@ -2988,6 +3232,7 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops,
#elif defined(CAIRO_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
+ , SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
#ifndef CAIRO_CANVAS_NO_CHUNKS
, SpiceVirtMapping *virt_mapping
@@ -3020,6 +3265,7 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops,
return 0;
}
#endif
+ canvas->surfaces = surfaces;
canvas->glz_data.decoder = glz_decoder;
if (depth == 16) {
diff --git a/common/canvas_base.h b/common/canvas_base.h
index bed1e1b..0a663bd 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 5eb31fe..d127180 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -1724,6 +1724,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 +1743,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 8b8f847..73d6978 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 f69c920..3fd49f2 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 29737ec..6d23629 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 17bf24c..88059f6 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 a2b441d..ef8652c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -395,6 +395,7 @@ typedef struct ImageItem {
int height;
int stride;
int top_down;
+ int surface_id;
uint8_t data[0];
} ImageItem;
@@ -459,6 +460,7 @@ typedef struct __attribute__ ((__packed__)) RedImage {
SpiceQUICData quic;
SpiceLZRGBData lz_rgb;
SpiceLZPLTData lz_plt;
+ SpiceSurface surface;
};
} RedImage;
@@ -611,6 +613,8 @@ typedef struct GlzSharedDictionary {
int migrate_freeze;
} GlzSharedDictionary;
+#define NUM_SURFACES 10000
+
struct DisplayChannel {
RedChannel base;
@@ -638,7 +642,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 {
@@ -796,8 +800,14 @@ typedef enum {
BITMAP_GRADUAL_FALSE,
} 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;
@@ -819,6 +829,7 @@ struct Drawable {
BitmapGradualType copy_bitmap_graduality;
uint32_t group_id;
uint8_t *self_bitmap;
+ DependItem depend_items[3];
};
typedef struct _Drawable _Drawable;
@@ -858,7 +869,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
@@ -905,10 +925,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;
@@ -988,14 +1009,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);
@@ -1068,6 +1089,31 @@ 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)
+{
+ if (surface_id >= worker->n_surfaces) {
+ red_printf("hrmm %d", surface_id);
+ }
+ if (!worker->surfaces[surface_id].context.canvas) {
+ red_printf("hrmm2 %d", 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;
@@ -1343,11 +1389,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);
}
@@ -1367,6 +1447,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)) {
@@ -1530,40 +1612,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)
{
- RedSurface *surface = &worker->surface;
+ 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;
+
+ validate_surface(worker, surface_id);
+ surface = &worker->surfaces[surface_id];
- PANIC_ON(!surface->context.canvas);
- __red_destroy_surface(worker);
+ 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);
@@ -1573,6 +1677,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) {
@@ -1586,6 +1725,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
@@ -1657,9 +1799,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--;
}
@@ -1673,6 +1835,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--;
}
@@ -1718,9 +1881,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;
@@ -1756,11 +1919,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);
}
@@ -1838,19 +2001,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
@@ -1870,16 +2033,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;
}
@@ -1888,7 +2051,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;
@@ -1922,7 +2085,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 {
@@ -1942,7 +2105,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);
}
}
}
@@ -1983,7 +2146,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)) {
@@ -2046,7 +2209,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)) {
@@ -2113,8 +2276,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++;
}
@@ -3165,14 +3334,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;
@@ -3286,10 +3454,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))) {
@@ -3301,19 +3469,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));
@@ -3432,12 +3599,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) {
@@ -3446,7 +3612,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
@@ -3509,7 +3674,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;
@@ -3522,12 +3687,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) {
@@ -3556,14 +3721,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);
}
@@ -3574,11 +3743,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);
@@ -3590,7 +3766,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;
@@ -3599,7 +3775,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;
@@ -3619,6 +3796,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);
}
@@ -3639,6 +3817,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
@@ -3653,15 +3832,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
@@ -3687,6 +3933,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;
@@ -3697,7 +3945,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++;
@@ -3710,6 +3969,47 @@ 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_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;
@@ -3841,6 +4141,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];
@@ -4061,6 +4381,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");
}
@@ -4086,6 +4409,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);
@@ -4145,8 +4469,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);
@@ -4286,24 +4618,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;
@@ -4365,15 +4703,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;
}
@@ -4394,23 +4737,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;
@@ -4419,21 +4773,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
@@ -4626,7 +4985,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;
@@ -4643,6 +5002,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");
}
@@ -4678,40 +5043,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);
@@ -6023,6 +6391,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);
@@ -6190,7 +6575,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);
@@ -6198,7 +6583,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);
@@ -6207,7 +6592,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);
@@ -6215,27 +6600,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);
@@ -6243,28 +6628,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);
@@ -6273,7 +6658,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);
@@ -6282,7 +6667,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);
@@ -6476,7 +6861,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;
@@ -6899,7 +7284,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;
@@ -7148,8 +7533,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);
}
@@ -7166,7 +7549,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);
}
@@ -7392,11 +7774,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)
@@ -7467,7 +7856,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;
@@ -7479,7 +7869,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;
}
@@ -7569,34 +7960,43 @@ 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");
}
PANIC_ON(surface->context.canvas);
- ASSERT(surface_id == 0);
surface->context.canvas_draws_on_surface = FALSE;
surface->context.width = width;
@@ -7604,8 +8004,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,
@@ -7613,7 +8017,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;
}
@@ -7621,9 +8026,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;
}
}
@@ -7683,7 +8088,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);
}
@@ -7734,10 +8139,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);
@@ -8335,7 +8740,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);
}
}
@@ -8527,12 +8932,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);
}
@@ -8572,12 +8982,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);
@@ -8593,8 +9005,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;
@@ -8603,10 +9016,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);
@@ -8626,7 +9051,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;
@@ -8661,7 +9089,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);
}
@@ -8697,12 +9124,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;
@@ -8821,17 +9248,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);
@@ -8973,8 +9406,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);
@@ -9005,6 +9438,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 141caee..54577db 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 674fae0..6d76b9e 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);
commit d850a44051c1d7fe531d27ec525927a365e8a53e
Author: Izik Eidus <ieidus at redhat.com>
Date: Wed Mar 31 01:45:49 2010 +0300
qxl device add off screen support
Signed-off-by: Izik Eidus <ieidus at redhat.com>
diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c
index 890d521..53b562b 100644
--- a/qemu/hw/qxl.c
+++ b/qemu/hw/qxl.c
@@ -19,7 +19,7 @@
//#define QXL_IO_MEM
-#define QXL_VRAM_SIZE 4096
+#define QXL_VRAM_SIZE 1024 * 1024 * 256
#define QXL_DEFAULT_COMPRESSION_LEVEL 0
#define QXL_SHARED_VGA_MODE FALSE
#define QXL_SAVE_VERSION 3
@@ -345,6 +345,7 @@ static void _qxl_get_init_info(PCIQXLDevice *d, QXLDevInitInfo *info)
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
info->qxl_ram_size = d->state.rom->num_pages << TARGET_PAGE_BITS;
+ info->n_surfaces = 10000;
}
static int qxl_get_ring_command(PCIQXLDevice *d, QXLCommandExt *cmd_ext, QXLCommandRing *ring,
@@ -413,9 +414,10 @@ static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommandExt *cmd_ext)
return 1;
}
-static const Rect *_qxl_get_update_area(PCIQXLDevice *d)
+static void _qxl_get_update_area(PCIQXLDevice *d, const Rect **rect, UINT32 **surface_id)
{
- return &d->state.ram->update_area;
+ *rect = &d->state.ram->update_area;
+ *surface_id = &d->state.ram->update_surface;
}
static int _qxl_req_cmd_notification(PCIQXLDevice *d)
@@ -1197,6 +1199,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
case QXL_IO_DESTROY_SURFACE_WAIT:
d->worker->destroy_surface_wait(d->worker, val);
break;
+ case QXL_IO_DESTROY_ALL_SURFACES:
+ d->worker->destroy_surfaces(d->worker);
+ break;
default:
printf("%s: unexpected addr 0x%x val 0x%x\n", __FUNCTION__, addr, val);
}
@@ -1269,6 +1274,10 @@ static void vram_map(PCIDevice *d, int region_num,
#else
cpu_register_physical_memory(addr, size, s->vram_offset | IO_MEM_RAM);
#endif
+ s->address_ranges[1].virt_start = (unsigned long)s->vram;
+ s->address_ranges[1].virt_end = s->address_ranges[1].virt_start + size;
+ s->address_ranges[1].phys_start = addr;
+ s->address_ranges[1].phys_end = s->address_ranges[1].phys_start + size;
}
@@ -1342,6 +1351,8 @@ static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size,
rom->slots_start = 1;
rom->slots_end = NUM_MEMSLOTS - 1;
+ rom->n_surfaces = 10000;
+
*max_fb = 0;
modes->n_modes = sizeof(qxl_modes) / sizeof(QXLMode);
@@ -1468,6 +1479,10 @@ static void qxl_vga_update(void)
}
image = (QXLImage *)(drawable + 1);
+ drawable->surface_id = 0;
+ drawable->surfaces_dest[0] = -1;
+ drawable->surfaces_dest[1] = -1;
+ drawable->surfaces_dest[2] = -1;
drawable->bbox = *dirty_rect;
drawable->clip.type = CLIP_TYPE_NONE;
drawable->clip.data = 0;
@@ -1795,9 +1810,9 @@ int qxl_has_command(QXLDevRef dev_ref)
return _qxl_has_command((PCIQXLDevice *)dev_ref);
}
-const Rect *qxl_get_update_area(QXLDevRef dev_ref)
+void qxl_get_update_area(QXLDevRef dev_ref, const Rect **rect, UINT32 **surface_id)
{
- return _qxl_get_update_area((PCIQXLDevice *)dev_ref);
+ _qxl_get_update_area((PCIQXLDevice *)dev_ref, rect, surface_id);
}
int qxl_flush_resources(QXLDevRef dev_ref)
@@ -1879,9 +1894,9 @@ static int interface_req_cursor_notification(QXLInterface *qxl)
return _qxl_req_cursor_notification(((Interface *)qxl)->d);
}
-static const struct Rect *interface_get_update_area(QXLInterface *qxl)
+static void interface_get_update_area(QXLInterface *qxl, const Rect **rect, UINT32 **surface_id)
{
- return _qxl_get_update_area(((Interface *)qxl)->d);
+ _qxl_get_update_area(((Interface *)qxl)->d, rect, surface_id);
}
static void interface_notify_update(QXLInterface *qxl, uint32_t update_id)
@@ -2204,13 +2219,13 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset,
d->state.vram_offset = vram_offset + rom_size + qxl_ram_size;
d->state.vram_size = msb_mask(vram_size - (qxl_ram_size + rom_size));
- d->state.address_ranges = (QXLAddressRange *)malloc(sizeof(QXLAddressRange) * (num_ranges + 1));
+ d->state.address_ranges = (QXLAddressRange *)malloc(sizeof(QXLAddressRange) * (num_ranges + 2));
PANIC_ON(!d->state.address_ranges);
qxl_reset_device_address_ranges(d);
for (i = 0; i < num_ranges; ++i) {
- d->state.address_ranges[i + 1] = address_ranges[i];
+ d->state.address_ranges[i + 2] = address_ranges[i];
}
- d->state.num_ranges = num_ranges + 1;
+ d->state.num_ranges = num_ranges + 2;
d->state.group_ids_flip[0] = 0;
d->state.group_ids_flip[1] = 1;
diff --git a/qemu/hw/qxl_dev.h b/qemu/hw/qxl_dev.h
index cba9e3e..122b8a2 100644
--- a/qemu/hw/qxl_dev.h
+++ b/qemu/hw/qxl_dev.h
@@ -50,6 +50,8 @@ enum {
QXL_IO_CREATE_PRIMARY,
QXL_IO_DESTROY_PRIMARY,
QXL_IO_DESTROY_SURFACE_WAIT,
+ QXL_IO_DESTROY_ALL_SURFACES,
+ QXL_IO_NOTIFY_SURFACES_OOM,
QXL_IO_RANGE_SIZE
};
@@ -71,6 +73,7 @@ typedef struct ATTR_PACKED QXLRom {
UINT8 slot_gen_bits;
UINT8 slot_id_bits;
UINT8 slot_generation;
+ UINT32 n_surfaces;
} QXLRom;
typedef struct ATTR_PACKED QXLMode {
@@ -149,6 +152,7 @@ typedef struct ATTR_PACKED QXLRam {
QXLCursorRing cursor_ring;
QXLReleaseRing release_ring;
Rect update_area;
+ UINT32 update_surface;
QXLMemSlot mem_slot;
QXLSurfaceCreate create_surface;
UINT64 flags;
@@ -180,6 +184,7 @@ typedef struct ATTR_PACKED QXLUpdateCmd {
QXLReleaseInfo release_info;
Rect area;
UINT32 update_id;
+ UINT32 surface_id;
} QXLUpdateCmd;
typedef struct ATTR_PACKED QXLCursor {
@@ -254,6 +259,7 @@ typedef struct ATTR_PACKED QXLCopyBits {
typedef struct ATTR_PACKED QXLDrawable {
QXLReleaseInfo release_info;
+ uint32_t surface_id;
UINT8 effect;
UINT8 type;
UINT8 self_bitmap;
@@ -261,6 +267,8 @@ typedef struct ATTR_PACKED QXLDrawable {
Rect bbox;
Clip clip;
UINT32 mm_time;
+ INT32 surfaces_dest[3];
+ Rect surfaces_rects[3];
union {
Fill fill;
Opaque opaque;
diff --git a/qemu/hw/qxl_interface.h b/qemu/hw/qxl_interface.h
index 8d37219..1de7e25 100644
--- a/qemu/hw/qxl_interface.h
+++ b/qemu/hw/qxl_interface.h
@@ -95,7 +95,7 @@ int qxl_req_cmd_notification(QXLDevRef dev_ref);
int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommandExt *cmd);
int qxl_req_cursor_notification(QXLDevRef dev_ref);
int qxl_has_command(QXLDevRef dev_ref);
-const Rect *qxl_get_update_area(QXLDevRef dev_ref);
+void qxl_get_update_area(QXLDevRef dev_ref, const Rect **rect, uint32_t **surface_id);
int qxl_flush_resources(QXLDevRef dev_ref);
void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size);
void *qxl_get_save_data(QXLDevRef dev_ref);
commit 1a2e4c90a21b5115424ad2f1b940c1ee3d3cbbe3
Author: Izik Eidus <ieidus at redhat.com>
Date: Wed Mar 31 01:47:12 2010 +0300
qxl driver: add off screen supprot
Signed-off-by: Izik Eidus <ieidus at redhat.com>
diff --git a/display/brush.c b/display/brush.c
index 802c0a9..d69cb76 100644
--- a/display/brush.c
+++ b/display/brush.c
@@ -315,7 +315,8 @@ BOOL APIENTRY DrvRealizeBrush(BRUSHOBJ *brush, SURFOBJ *target, SURFOBJ *pattern
static _inline BOOL GetPattern(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *pattern,
- InternalBrush *brush)
+ InternalBrush *brush, INT32 *surface_dest,
+ SpiceRect *surface_rect)
{
HSURF hsurf;
SURFOBJ *surf_obj;
@@ -342,7 +343,9 @@ static _inline BOOL GetPattern(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *p
area.right = brush->size.cx;
area.bottom = brush->size.cy;
- if (!QXLGetBitmap(pdev, drawable, pattern, surf_obj, &area, NULL, &key, TRUE)) {
+ CopyRect(surface_rect, &area);
+
+ if (!QXLGetBitmap(pdev, drawable, pattern, surf_obj, &area, NULL, &key, TRUE, surface_dest)) {
goto error_2;
}
@@ -361,7 +364,8 @@ error_1:
BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, SpiceBrush *qxl_brush,
- BRUSHOBJ *brush, POINTL *brush_pos)
+ BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
+ SpiceRect *surface_rect)
{
DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
ASSERT(pdev, brush);
@@ -377,7 +381,8 @@ BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, SpiceBrush *qxl_brush,
qxl_brush->type = SPICE_BRUSH_TYPE_PATTERN;
qxl_brush->u.pattern.pos.x = brush_pos->x;
qxl_brush->u.pattern.pos.y = brush_pos->y;
- if (!GetPattern(pdev, drawable, &qxl_brush->u.pattern.pat, brush->pvRbrush)) {
+ if (!GetPattern(pdev, drawable, &qxl_brush->u.pattern.pat, brush->pvRbrush,
+ surface_dest, surface_rect)) {
return FALSE;
}
} else {
diff --git a/display/dd.c b/display/dd.c
new file mode 100644
index 0000000..a9c0aac
--- /dev/null
+++ b/display/dd.c
@@ -0,0 +1,118 @@
+#include <ddrawi.h>
+#include <ddraw.h>
+#include <dxmini.h>
+#include "os_dep.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+#include "ioaccess.h"
+#include "qxldd.h"
+
+static UINT8 get_depth(PDev *pdev)
+{
+ if (pdev->bitmap_format == BMF_32BPP) {
+ return 32;
+ } else {
+ return 16;
+ }
+}
+
+BOOL DrvGetDirectDrawInfo(DHPDEV dhpdev, DD_HALINFO *pHallInfo,
+ DWORD *pdvNumHeaps, VIDEOMEMORY *pvmList,
+ DWORD *pdvNumFourCCCodes,
+ DWORD *pdvFourCC)
+{
+ PDev *pdev;
+ DWORD offset;
+
+ pdev = (PDev *)dhpdev;
+
+ *pdvNumHeaps = 1;
+ *pdvNumFourCCCodes = 0;
+
+ if (!pdev->dd_slot_initialized) {
+ return FALSE;
+ }
+
+ offset = pdev->resolution.cy * pdev->stride;
+
+ if (pvmList) {
+ VIDEOMEMORY *pvmobj = pvmList;
+
+ pvmobj->dwFlags = VIDMEM_ISLINEAR;
+
+ pvmobj->fpStart = (FLATPTR)pdev->fb;
+ pvmobj->fpEnd = pvmobj->fpStart + pdev->fb_size - 1;
+
+ pvmobj->ddsCaps.dwCaps = 0;
+ pvmobj->ddsCapsAlt.dwCaps = 0;
+
+ pdev->pvmList = pvmList;
+ }
+
+ memset(pHallInfo, 0, sizeof(DD_HALINFO));
+
+ pHallInfo->vmiData.pvPrimary = pdev->fb;
+ pHallInfo->vmiData.fpPrimary = 0;
+
+ pHallInfo->dwSize = sizeof (DD_HALINFO);
+
+ pHallInfo->vmiData.dwFlags = 0;
+ pHallInfo->vmiData.dwDisplayWidth = pdev->resolution.cx;
+ pHallInfo->vmiData.dwDisplayHeight = pdev->resolution.cy;
+ pHallInfo->vmiData.lDisplayPitch = pdev->stride;
+ pHallInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
+ pHallInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
+
+ pHallInfo->vmiData.ddpfDisplay.dwRGBBitCount = get_depth(pdev);
+
+ pHallInfo->vmiData.ddpfDisplay.dwRBitMask = pdev->red_mask;
+ pHallInfo->vmiData.ddpfDisplay.dwGBitMask = pdev->green_mask;
+ pHallInfo->vmiData.ddpfDisplay.dwBBitMask = pdev->blue_mask;
+
+ pHallInfo->vmiData.dwOffscreenAlign = 4;
+ pHallInfo->vmiData.dwOverlayAlign = 4;
+ pHallInfo->vmiData.dwTextureAlign = 4;
+ pHallInfo->vmiData.dwZBufferAlign = 4;
+ pHallInfo->vmiData.dwAlphaAlign = 4;
+
+ pHallInfo->ddCaps.dwSize = sizeof (DDCORECAPS);
+ pHallInfo->ddCaps.dwVidMemTotal = pdev->fb_size;
+ pHallInfo->ddCaps.dwVidMemFree = pdev->fb_size;
+
+ pdev->dd_initialized = TRUE;
+
+ return TRUE;
+}
+
+DWORD CALLBACK QxlCanCreateSurface(PDD_CANCREATESURFACEDATA data)
+{
+ return DDHAL_DRIVER_NOTHANDLED;
+}
+
+DWORD CALLBACK QxlFlip(PDD_FLIPDATA lpFlip)
+{
+ return DDHAL_DRIVER_NOTHANDLED;
+}
+
+BOOL DrvEnableDirectDraw(DHPDEV dhpdev, DD_CALLBACKS *pCallBacks,
+ DD_SURFACECALLBACKS *pSurfaceCallBacks,
+ DD_PALETTECALLBACKS *pPaletteCallBacks)
+{
+ memset(pCallBacks, 0, sizeof (DD_CALLBACKS));
+ memset(pSurfaceCallBacks, 0, sizeof (DD_SURFACECALLBACKS));
+ memset(pPaletteCallBacks, 0, sizeof (DD_PALETTECALLBACKS));
+
+ pCallBacks->dwSize = sizeof (DD_CALLBACKS);
+ pCallBacks->CanCreateSurface = QxlCanCreateSurface;
+
+ pSurfaceCallBacks->dwSize = sizeof (DD_SURFACECALLBACKS);
+ pSurfaceCallBacks->Flip = QxlFlip;
+
+ pPaletteCallBacks->dwSize = sizeof (DD_PALETTECALLBACKS);
+
+ return TRUE;
+}
+
+void DrvDisableDirectDraw(DHPDEV dhpdev)
+{
+}
diff --git a/display/dd.h b/display/dd.h
new file mode 100644
index 0000000..ffcd8e1
--- /dev/null
+++ b/display/dd.h
@@ -0,0 +1,15 @@
+#ifndef DD_H
+#define DD_H
+
+BOOL DrvGetDirectDrawInfo(DHPDEV dhpdev, DD_HALINFO *pHallInfo,
+ DWORD *pdvNumHeaps, VIDEOMEMORY *pvmList,
+ DWORD *pdvNumFourCCCodes,
+ DWORD *pdvFourCC);
+
+BOOL DrvEnableDirectDraw(DHPDEV dhpdev, DD_CALLBACKS *pCallBacks,
+ DD_SURFACECALLBACKS *pSurfaceCallBacks,
+ DD_PALETTECALLBACKS *pPaletteCallBacks);
+
+void DrvDisableDirectDraw(DHPDEV dhpdev);
+
+#endif
diff --git a/display/driver.c b/display/driver.c
index d3737e3..030917b 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -35,6 +35,7 @@
#include "mspace.h"
#include "res.h"
#include "surface.h"
+#include "dd.h"
#define DEVICE_NAME L"qxldd"
@@ -61,6 +62,12 @@ static DRVFN drv_calls[] = {
{INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP},
{INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt},
{INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend},
+ {INDEX_DrvCreateDeviceBitmap, (PFN)DrvCreateDeviceBitmap},
+ {INDEX_DrvDeleteDeviceBitmap, (PFN)DrvDeleteDeviceBitmap},
+
+ {INDEX_DrvGetDirectDrawInfo, (PFN)DrvGetDirectDrawInfo},
+ {INDEX_DrvEnableDirectDraw, (PFN)DrvEnableDirectDraw},
+ {INDEX_DrvDisableDirectDraw, (PFN)DrvDisableDirectDraw},
#ifdef CALL_TEST
{INDEX_DrvFillPath, (PFN)DrvFillPath},
@@ -117,7 +124,7 @@ void DebugPrint(PDev *pdev, int level, const char *message, ...)
{
va_list ap;
- if (level > (pdev ? (int)*pdev->log_level : DBG_LEVEL)) {
+ if (level > (pdev ? (int)*pdev->log_level : DBG_LEVEL) && level != 211) {
return;
}
va_start(ap, message);
@@ -512,9 +519,14 @@ DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ig
goto err3;
}
+ if (!(pdev->cmd_sem = EngCreateSemaphore())) {
+ DEBUG_PRINT((NULL, 0, "%s: create cmd sem failed\n", __FUNCTION__));
+ goto err4;
+ }
+
if (!ResInit(pdev)) {
DEBUG_PRINT((NULL, 0, "%s: init res failed\n", __FUNCTION__));
- goto err4;
+ goto err5;
}
RtlCopyMemory(dev_caps, &gdi_info, dev_caps_size);
@@ -523,6 +535,8 @@ DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ig
DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
return(DHPDEV)pdev;
+err5:
+ EngDeleteSemaphore(pdev->cmd_sem);
err4:
EngDeleteSemaphore(pdev->print_sem);
@@ -543,8 +557,10 @@ VOID DrvDisablePDEV(DHPDEV in_pdev)
PDev* pdev = (PDev*)in_pdev;
DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+ EngFreeMem(pdev->surfaces_info);
ResDestroy(pdev);
DestroyPalette(pdev);
+ EngDeleteSemaphore(pdev->cmd_sem);
EngDeleteSemaphore(pdev->malloc_sem);
EngDeleteSemaphore(pdev->print_sem);
EngFreeMem(pdev);
@@ -591,6 +607,12 @@ static void DestroyPrimarySurface(PDev *pdev)
WRITE_PORT_UCHAR(pdev->destroy_primary_port, 0);
}
+static void DestroyAllSurfaces(PDev *pdev)
+{
+ HideMouse(pdev);
+ WRITE_PORT_UCHAR(pdev->destroy_all_surfaces_port, 0);
+}
+
BOOL SetHardwareMode(PDev *pdev)
{
VIDEO_MODE_INFORMATION video_info;
@@ -624,6 +646,49 @@ static VOID UpdateMainSlot(PDev *pdev, MemSlot *slot)
pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
}
+static void RemoveVRamSlot(PDev *pdev)
+{
+ WRITE_PORT_UCHAR(pdev->memslot_del_port, pdev->dd_mem_slot);
+ pdev->dd_slot_initialized = FALSE;
+}
+
+static BOOLEAN CreateVRamSlot(PDev *pdev)
+{
+ QXLMemSlot *slot;
+ UINT64 high_bits;
+ UINT8 slot_id = pdev->main_mem_slot + 1;
+
+ if (slot_id >= pdev->num_mem_slot) {
+ return FALSE;
+ }
+
+ pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
+
+
+ *pdev->ram_slot_start = pdev->fb_phys;
+ *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
+
+ WRITE_PORT_UCHAR(pdev->memslot_add_port, slot_id);
+
+ pdev->dd_mem_slot = slot_id;
+
+ pdev->mem_slots[slot_id].slot.generation = *pdev->slots_generation;
+ pdev->mem_slots[slot_id].slot.start_phys_addr = pdev->fb_phys;
+ pdev->mem_slots[slot_id].slot.end_phys_addr = pdev->fb_phys + pdev->fb_size;
+ pdev->mem_slots[slot_id].slot.start_virt_addr = (UINT64)pdev->fb;
+ pdev->mem_slots[slot_id].slot.end_virt_addr = (UINT64)pdev->fb + pdev->fb_size;
+
+ high_bits = slot_id << pdev->slot_gen_bits;
+ high_bits |= pdev->mem_slots[slot_id].slot.generation;
+ high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
+ pdev->mem_slots[slot_id].high_bits = high_bits;
+
+ pdev->dd_slot_initialized = TRUE;
+
+ return TRUE;
+}
+
+
BOOL PrepareHardware(PDev *pdev)
{
VIDEO_MEMORY video_mem;
@@ -671,6 +736,7 @@ BOOL PrepareHardware(PDev *pdev)
pdev->update_area_port = dev_info.update_area_port;
pdev->update_area = dev_info.update_area;
+ pdev->update_surface = dev_info.update_surface;
pdev->mm_clock = dev_info.mm_clock;
@@ -680,6 +746,14 @@ BOOL PrepareHardware(PDev *pdev)
pdev->log_buf = dev_info.log_buf;
pdev->log_level = dev_info.log_level;
+ pdev->n_surfaces = dev_info.n_surfaces;
+ if (!(pdev->surfaces_info = (SurfaceInfo *)EngAllocMem(FL_ZERO_MEMORY,
+ sizeof(SurfaceInfo) *
+ pdev->n_surfaces, ALLOC_TAG))) {
+ DEBUG_PRINT((NULL, 0, "%s: surfaces_info alloc failed\n", __FUNCTION__));
+ return FALSE;
+ }
+
pdev->mem_slots = EngAllocMem(FL_ZERO_MEMORY, sizeof(PMemSlot) * dev_info.num_mem_slot,
ALLOC_TAG);
if (!pdev->mem_slots) {
@@ -687,6 +761,9 @@ BOOL PrepareHardware(PDev *pdev)
return FALSE;
}
+ pdev->slots_generation = dev_info.slots_generation;
+ pdev->ram_slot_start = dev_info.ram_slot_start;
+ pdev->ram_slot_end = dev_info.ram_slot_end;
pdev->slot_id_bits = dev_info.slot_id_bits;
pdev->slot_gen_bits = dev_info.slot_gen_bits;
pdev->main_mem_slot = dev_info.main_mem_slot_id;
@@ -706,8 +783,13 @@ BOOL PrepareHardware(PDev *pdev)
video_mem_Info.FrameBufferBase, video_mem_Info.FrameBufferLength));
pdev->fb = (BYTE*)video_mem_Info.FrameBufferBase;
pdev->fb_size = video_mem_Info.FrameBufferLength;
+ pdev->fb_phys = dev_info.fb_phys;
pdev->destroy_surface_wait_port = dev_info.destroy_surface_wait_port;
+ pdev->destroy_all_surfaces_port = dev_info.destroy_all_surfaces_port;
+ pdev->memslot_add_port = dev_info.memslot_add_port;
+ pdev->memslot_del_port = dev_info.memslot_del_port;
+
pdev->create_primary_port = dev_info.create_primary_port;
pdev->destroy_primary_port = dev_info.destroy_primary_port;
@@ -718,6 +800,10 @@ BOOL PrepareHardware(PDev *pdev)
pdev->dev_id = dev_info.dev_id;
+ pdev->dd_initialized = FALSE;
+
+ CreateVRamSlot(pdev);
+
DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit: 0x%lx %ul\n", __FUNCTION__, pdev,
pdev->fb, pdev->fb_size));
return TRUE;
@@ -746,7 +832,7 @@ static VOID UnmapFB(PDev *pdev)
}
}
-VOID EnableQXLSurface(PDev *pdev)
+VOID EnableQXLPrimarySurface(PDev *pdev)
{
UINT32 depth;
@@ -777,7 +863,6 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
DWORD length;
QXLPHYSICAL phys_mem;
UINT8 *base_mem;
- DrawArea drawarea;
DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
@@ -788,19 +873,12 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
InitResources(pdev);
if (!(surf = (HSURF)CreateDeviceBitmap(pdev, pdev->resolution, pdev->bitmap_format, &phys_mem,
- &base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
+ &base_mem, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
DEBUG_PRINT((NULL, 0, "%s: create device surface failed, 0x%lx\n",
__FUNCTION__, pdev));
goto err;
}
- if (!CreateDrawArea(pdev, &drawarea, base_mem, pdev->resolution.cx, pdev->resolution.cy)) {
- goto err;
- }
-
- pdev->draw_bitmap = drawarea.bitmap;
- pdev->draw_surf = drawarea.surf_obj;
-
DEBUG_PRINT((NULL, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
"0x%lx, 0x%lx, %lu, NULL)\n",
__FUNCTION__,
@@ -814,7 +892,7 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
pdev->surf_phys = phys_mem;
pdev->surf_base = base_mem;
- EnableQXLSurface(pdev);
+ EnableQXLPrimarySurface(pdev);
DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
return surf;
@@ -825,7 +903,7 @@ err:
return NULL;
}
-VOID DisableQXLSurface(PDev *pdev)
+VOID DisableQXLPrimarySurface(PDev *pdev)
{
DrawArea drawarea;
@@ -836,6 +914,11 @@ VOID DisableQXLSurface(PDev *pdev)
}
}
+VOID DisableQXLAllSurfaces(PDev *pdev)
+{
+ DestroyAllSurfaces(pdev);
+}
+
VOID DrvDisableSurface(DHPDEV in_pdev)
{
PDev *pdev = (PDev*)in_pdev;
@@ -843,12 +926,13 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
- DisableQXLSurface(pdev);
+ DisableQXLPrimarySurface(pdev);
+ //DisableQXLAllSurfaces(pdev);
UnmapFB(pdev);
if (pdev->surf) {
- DeleteDeviceBitmap(pdev->surf);
+ DeleteDeviceBitmap(pdev, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
pdev->surf = NULL;
}
@@ -860,6 +944,11 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
pdev->draw_bitmap = NULL;
}
+ if (pdev->surfaces_info) {
+ EngFreeMem(pdev->surfaces_info);
+ pdev->surfaces_info = NULL;
+ }
+
if (pdev->mem_slots) {
EngFreeMem(pdev->mem_slots);
pdev->mem_slots = NULL;
@@ -875,9 +964,11 @@ BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
if (enable) {
InitResources(pdev);
- EnableQXLSurface(pdev);
+ EnableQXLPrimarySurface(pdev);
+ CreateVRamSlot(pdev);
} else {
- DisableQXLSurface(pdev);
+ DisableQXLPrimarySurface(pdev);
+ RemoveVRamSlot(pdev);
}
DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit TRUE\n", __FUNCTION__, pdev));
return TRUE;
@@ -1217,7 +1308,7 @@ BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOB
}
}
- if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip, GetSurfaceId(surf)))) {
return FALSE;
}
@@ -1226,7 +1317,8 @@ BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOB
if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
- } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos)) {
+ } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos,
+ &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
goto err;
}
@@ -1266,6 +1358,51 @@ err:
return FALSE;
}
+HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
+{
+ PDev *pdev;
+ UINT8 *base_mem;
+ UINT32 surface_id;
+ QXLPHYSICAL phys_mem;
+ HBITMAP hbitmap;
+
+ pdev = (PDev *)dhpdev;
+
+ if (!pdev->dd_initialized) {
+ return 0;
+ }
+
+ surface_id = GetFreeSurface(pdev);
+ if (!surface_id) {
+ goto out_error;
+ }
+
+ hbitmap = CreateDeviceBitmap(pdev, size, pdev->bitmap_format, &phys_mem, &base_mem, surface_id,
+ DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+ if (!hbitmap) {
+ goto out_error;
+ }
+
+ return hbitmap;
+
+ // to optimize the failure case
+out_error:
+ return 0;
+}
+
+VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
+{
+ UINT32 surface_id;
+ PDev *pdev;
+ SurfaceInfo *surface;
+
+ surface = (SurfaceInfo *)dhsurf;
+ pdev = surface->pdev;
+ surface_id = surface - pdev->surfaces_info;
+
+ DeleteDeviceBitmap(pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+}
+
#ifdef CALL_TEST
void CountCall(PDev *pdev, int counter)
diff --git a/display/qxldd.h b/display/qxldd.h
index 80dd30a..f1623d1 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -166,6 +166,8 @@ typedef struct DevRes {
struct InternalPalette *palette_cache[PALETTE_HASH_SIZE];
UINT32 num_palettes;
+ UINT8 *surfaces_used;
+
#ifdef DBG
int num_free_pages;
int num_outputs;
@@ -187,6 +189,20 @@ typedef struct DevRes {
#define SSE_MASK 15
#define SSE_ALIGN 16
+
+typedef struct DrawArea {
+ HSURF bitmap;
+ SURFOBJ* surf_obj;
+ UINT8 *base_mem;
+} DrawArea;
+
+typedef struct PDev PDev;
+
+typedef struct SurfaceInfo {
+ DrawArea draw_area;
+ PDev *pdev;
+} SurfaceInfo;
+
typedef struct PDev {
HANDLE driver;
HDEV eng;
@@ -197,8 +213,14 @@ typedef struct PDev {
SIZEL resolution;
UINT32 max_bitmap_size;
ULONG bitmap_format;
+
ULONG fb_size;
BYTE* fb;
+ UINT64 fb_phys;
+ UINT8 dd_initialized;
+ UINT8 dd_slot_initialized;
+ UINT8 dd_mem_slot;
+
ULONG stride;
FLONG red_mask;
FLONG green_mask;
@@ -229,12 +251,16 @@ typedef struct PDev {
HSEMAPHORE malloc_sem;
HSEMAPHORE print_sem;
+ HSEMAPHORE cmd_sem;
PMemSlot *mem_slots;
UINT8 num_mem_slot;
UINT8 main_mem_slot;
UINT8 slot_id_bits;
UINT8 slot_gen_bits;
+ UINT8 *slots_generation;
+ UINT64 *ram_slot_start;
+ UINT64 *ram_slot_end;
SPICE_ADDRESS va_slot_mask;
UINT32 num_io_pages;
@@ -245,6 +271,7 @@ typedef struct PDev {
UINT32 update_area_port;
SpiceRect *update_area;
+ UINT32 *update_surface;
UINT32 *mm_clock;
@@ -259,6 +286,9 @@ typedef struct PDev {
UINT32 create_primary_port;
UINT32 destroy_primary_port;
UINT32 destroy_surface_wait_port;
+ UINT32 memslot_add_port;
+ UINT32 memslot_del_port;
+ UINT32 destroy_all_surfaces_port;
UINT8* primary_memory_start;
UINT32 primary_memory_size;
@@ -273,6 +303,11 @@ typedef struct PDev {
UpdateTrace update_trace_items[NUM_UPDATE_TRACE_ITEMS];
UINT8 FPUSave[16 * 4 + 15];
+
+ UINT32 n_surfaces;
+ SurfaceInfo *surfaces_info;
+
+ VIDEOMEMORY *pvmList;
} PDev;
diff --git a/display/res.c b/display/res.c
index 041bf2e..318ea9c 100644
--- a/display/res.c
+++ b/display/res.c
@@ -15,6 +15,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <ddrawi.h>
+#include <ddraw.h>
+#include <dxmini.h>
#include "os_dep.h"
#include "res.h"
#include "ioaccess.h"
@@ -22,6 +25,8 @@
#include "mspace.h"
#include "quic.h"
#include "murmur_hash2a.h"
+#include "surface.h"
+#include "dd.h"
#if (WINVER < 0x0501)
#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
@@ -67,10 +72,12 @@ static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
#define PUSH_CMD(pdev) do { \
int notify; \
+ EngAcquireSemaphore(pdev->cmd_sem); \
SPICE_RING_PUSH(pdev->cmd_ring, notify); \
if (notify) { \
WRITE_PORT_UCHAR(pdev->notify_cmd_port, 0); \
} \
+ EngReleaseSemaphore(pdev->cmd_sem); \
} while (0);
#define PUSH_CURSOR_CMD(pdev) do { \
@@ -130,6 +137,15 @@ static _inline void DrawableAddRes(PDev *pdev, QXLDrawable *drawable, Resource *
AddRes(pdev, output, res);
}
+
+static _inline void SurfaceAddRes(PDev *pdev, QXLSurfaceCmd *surface, Resource *res)
+{
+ QXLOutput *output;
+
+ output = (QXLOutput *)((UINT8 *)surface - sizeof(QXLOutput));
+ AddRes(pdev, output, res);
+}
+
static _inline void CursorCmdAddRes(PDev *pdev, QXLCursorCmd *cmd, Resource *res)
{
QXLOutput *output;
@@ -311,6 +327,10 @@ void CleanGlobalRes()
EngFreeMem(global_res[i].dynamic);
global_res[i].dynamic = NULL;
}
+ if (global_res[i].surfaces_used) {
+ EngFreeMem(global_res[i].surfaces_used);
+ global_res[i].surfaces_used = NULL;
+ }
}
EngFreeMem(global_res);
global_res = NULL;
@@ -347,6 +367,12 @@ static void InitRes(PDev *pdev)
PANIC(pdev, "Res dynamic allocation failed\n");
}
+ pdev->Res.surfaces_used = EngAllocMem(FL_ZERO_MEMORY, sizeof(UINT8) * pdev->n_surfaces,
+ ALLOC_TAG);
+ if (!pdev->Res.surfaces_used) {
+ PANIC(pdev, "Res surfaces_used allocation failed\n");
+ }
+
pdev->Res.free_outputs = 0;
InitMspace(&pdev->Res, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
pdev->Res.update_id = *pdev->dev_update_id;
@@ -457,17 +483,21 @@ static QXLDrawable *GetDrawable(PDev *pdev)
return(QXLDrawable *)output->data;
}
-QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip)
+QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id)
{
QXLDrawable *drawable;
ASSERT(pdev, pdev && area);
drawable = GetDrawable(pdev);
+ drawable->surface_id = surface_id;
drawable->type = type;
drawable->effect = QXL_EFFECT_BLEND;
drawable->self_bitmap = 0;
drawable->mm_time = *pdev->mm_clock;
+ drawable->surfaces_dest[0] = -1;
+ drawable->surfaces_dest[1] = - 1;
+ drawable->surfaces_dest[2] = -1;
CopyRect(&drawable->bbox, area);
if (!SetClip(pdev, clip, drawable)) {
@@ -489,23 +519,141 @@ void PushDrawable(PDev *pdev, QXLDrawable *drawable)
PUSH_CMD(pdev);
}
-_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT8 **base_mem,
- QXLPHYSICAL *phys_mem, UINT8 allocation_type)
+static QXLSurfaceCmd *GetSurfaceCmd(PDev *pdev)
+{
+ QXLOutput *output;
+
+ output = (QXLOutput *)AllocMem(pdev, sizeof(QXLOutput) + sizeof(QXLSurfaceCmd));
+ output->num_res = 0;
+ ((QXLSurfaceCmd *)output->data)->release_info.id = (UINT64)output;
+ DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
+ ONDBG(pdev->Res.num_outputs++); //todo: atomic
+ return(QXLSurfaceCmd *)output->data;
+}
+
+QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id)
+{
+ QXLSurfaceCmd *surface_cmd;
+
+ ASSERT(pdev, pdev && area);
+
+ surface_cmd = GetSurfaceCmd(pdev);
+ surface_cmd->surface_id = surface_id;
+ surface_cmd->type = type;
+ surface_cmd->flags = 0;
+
+ return surface_cmd;
+}
+
+void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd)
+{
+ QXLCommand *cmd;
+
+ WaitForCmdRing(pdev);
+ cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
+ cmd->type = QXL_CMD_SURFACE;
+ cmd->data = PA(pdev, surface_cmd, pdev->main_mem_slot);
+ PUSH_CMD(pdev);
+}
+
+
+_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT32 *stride,
+ UINT8 **base_mem, QXLPHYSICAL *phys_mem, UINT8 allocation_type)
{
DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
- ASSERT(pdev, allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
- ASSERT(pdev, x * y * depth /8 <= pdev->primary_memory_size);
+ switch (allocation_type) {
+ case DEVICE_BITMAP_ALLOCATION_TYPE_SURF0:
+ ASSERT(pdev, x * y * depth /8 <= pdev->primary_memory_size);
+ *base_mem = pdev->primary_memory_start;
+ *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+ *stride = x * depth / 8;
+ break;
+ case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
+ *base_mem = AllocMem(pdev, x * y * depth / 8);
+ *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+ *stride = x * depth / 8;
+ break;
+ case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM: {
+ SURFACEALIGNMENT surfacealignment;
+
+ memset(&surfacealignment, 0, sizeof(surfacealignment));
+ surfacealignment.Linear.dwStartAlignment = 4;
+ surfacealignment.Linear.dwPitchAlignment = 4;
+ *base_mem = (UINT8 *)HeapVidMemAllocAligned((LPVIDMEM)pdev->pvmList, x * depth / 8, y,
+ &surfacealignment, stride);
+ *phys_mem = PA(pdev, (PVOID)((UINT64)*base_mem), pdev->dd_mem_slot);
+ break;
+ }
+ default:
+ PANIC(pdev, "No allocation type");
+ }
+}
- *base_mem = pdev->primary_memory_start;
- *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+ UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
+{
+ GetSurfaceMemory(pdev, x, y, depth, stride, base_mem, surface_phys, allocation_type);
}
-BOOL QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
- UINT8 **base_mem, UINT8 allocation_type) {
- ASSERT(pdev, allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
- GetSurfaceMemory(pdev, x, y, depth, base_mem, surface_phys, allocation_type);
- return TRUE;
+void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type)
+{
+ if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM) {
+ FreeMem(pdev, base_mem);
+ }
+}
+
+typedef struct InternalDelSurface {
+ UINT32 surface_id;
+ UINT8 allocation_type;
+} InternalDelSurface;
+
+
+static void FreeDelSurface(PDev *pdev, Resource *res)
+{
+ InternalDelSurface *internal;
+ DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+ internal = (InternalDelSurface *)res->res;
+ switch (internal->allocation_type) {
+ case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
+ FreeMem(pdev, pdev->surfaces_info[internal->surface_id].draw_area.base_mem);
+ break;
+ case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
+ VidMemFree(pdev->pvmList->lpHeap,
+ (FLATPTR)pdev->surfaces_info[internal->surface_id].draw_area.base_mem);
+ break;
+ default:
+ PANIC(pdev, "bad allocation type");
+ }
+ FreeSurface(pdev, internal->surface_id);
+ FreeMem(pdev, res);
+
+ DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
+#define SURFACEDEL_ALLOC_BASE (sizeof(Resource) + sizeof(InternalDelSurface))
+
+void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type)
+{
+ Resource *surface_res;
+ InternalDelSurface *internal;
+ size_t alloc_size;
+
+ DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+ alloc_size = SURFACEDEL_ALLOC_BASE;
+ surface_res = AllocMem(pdev, alloc_size);
+
+ surface_res->refs = 1;
+ surface_res->free = FreeDelSurface;
+
+ internal = (InternalDelSurface *)surface_res->res;
+ internal->surface_id = surface_id;
+ internal->allocation_type = allocation_type;
+
+ SurfaceAddRes(pdev, surface, surface_res);
+ RELEASE_RES(pdev, surface_res);
}
static void FreePath(PDev *pdev, Resource *res)
@@ -1512,6 +1660,15 @@ static _inline void SaveFPU(PDev *pdev)
}
}
+static void FreeSurfaceImage(PDev *pdev, Resource *res)
+{
+ DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
+
+ FreeMem(pdev, res);
+
+ DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
+}
+
#define BITMAP_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
static _inline Resource *GetBitmapImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans,
@@ -1789,7 +1946,8 @@ static _inline UINT32 get_image_serial()
}
BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
- SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache)
+ SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
+ INT32 *surface_dest)
{
Resource *image_res;
InternalImage *internal;
@@ -1804,8 +1962,29 @@ BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SU
ASSERT(pdev, !hash_key || use_cache);
DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
if (surf->iType != STYPE_BITMAP) {
- DEBUG_PRINT((pdev, 0, "%s: copy from device doing nothing!!!\n", __FUNCTION__));
- return FALSE;
+ UINT32 alloc_size;
+
+ DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
+
+ alloc_size = sizeof(Resource) + sizeof(InternalImage);
+ image_res = AllocMem(pdev, alloc_size);
+
+ ONDBG(pdev->num_bits_pages++);
+ image_res->refs = 1;
+ image_res->free = FreeSurfaceImage;
+
+ internal = (InternalImage *)image_res->res;
+
+ internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+ *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
+
+ *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+
+ DrawableAddRes(pdev, drawable, image_res);
+
+ RELEASE_RES(pdev, image_res);
+
+ return TRUE;
}
if (area->left < 0 || area->right > surf->sizlBitmap.cx ||
@@ -1910,7 +2089,7 @@ BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SU
}
BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys,
- SURFOBJ *surf, SpiceRect *area)
+ SURFOBJ *surf, SpiceRect *area, INT32 *surface_dest)
{
Resource *image_res;
InternalImage *internal;
@@ -1922,7 +2101,6 @@ BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phy
INT32 height = area->bottom - area->top;
DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
- ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP && surf->iType == STYPE_BITMAP);
ASSERT(pdev, area->left >= 0 && area->right <= surf->sizlBitmap.cx &&
area->top >= 0 && area->bottom <= surf->sizlBitmap.cy);
@@ -1932,6 +2110,32 @@ BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phy
surf->sizlBitmap.cx, surf->sizlBitmap.cy, surf->hsurf,
surf->iBitmapFormat));
+ if (surf->iType != STYPE_BITMAP) {
+ UINT32 alloc_size;
+
+ DEBUG_PRINT((pdev, 9, "%s: copy from device\n", __FUNCTION__));
+
+ alloc_size = sizeof(Resource) + sizeof(InternalImage);
+ image_res = AllocMem(pdev, alloc_size);
+
+ ONDBG(pdev->num_bits_pages++);
+ image_res->refs = 1;
+ image_res->free = FreeSurfaceImage;
+
+ internal = (InternalImage *)image_res->res;
+
+ internal->image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
+ *surface_dest = internal->image.surface_image.surface_id = GetSurfaceId(surf);
+
+ *image_phys = PA(pdev, &internal->image, pdev->main_mem_slot);
+ DrawableAddRes(pdev, drawable, image_res);
+ RELEASE_RES(pdev, image_res);
+
+ return TRUE;
+ }
+
+ ASSERT(pdev, surf->iBitmapFormat == BMF_32BPP && surf->iType == STYPE_BITMAP);
+
//todo: use GetChachImage
// NOTE: Same BMF_DONTCACHE issue as in QXLGetBitmap
@@ -2024,7 +2228,7 @@ BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXL
}
BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, SpiceQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
- BOOL invers, LONG width, LONG height)
+ BOOL invers, LONG width, LONG height, INT32 *surface_dest)
{
SpiceRect area;
@@ -2046,7 +2250,8 @@ BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, SpiceQMask *qxl_mask, SURFOBJ
area.top = pos->y;
area.bottom = area.top + height;
- if (QXLGetBitmap(pdev, drawable, &qxl_mask->bitmap, mask, &area, NULL, NULL, TRUE)) {
+ if (QXLGetBitmap(pdev, drawable, &qxl_mask->bitmap, mask, &area, NULL, NULL, TRUE,
+ surface_dest)) {
qxl_mask->pos.x = area.left;
qxl_mask->pos.y = area.top;
return TRUE;
@@ -2082,7 +2287,7 @@ UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT3
}
#ifdef UPDATE_CMD
-void UpdateArea(PDev *pdev, RECTL *area)
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
{
QXLCommand *cmd;
QXLOutput *output;
@@ -2098,6 +2303,7 @@ void UpdateArea(PDev *pdev, RECTL *area)
CopyRect(&updat_cmd->area, area);
updat_cmd->update_id = ++pdev->Res.update_id;
+ updat_cmd->surface_id = surface_id;
WaitForCmdRing(pdev);
cmd = SPICE_RING_PROD_ITEM(pdev->cmd_ring);
@@ -2131,10 +2337,11 @@ void UpdateArea(PDev *pdev, RECTL *area)
#else
-void UpdateArea(PDev *pdev, RECTL *area)
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
{
DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
CopyRect(pdev->update_area, area);
+ *pdev->update_surface = surface_id;
WRITE_PORT_UCHAR(pdev->update_area_port, 0);
}
diff --git a/display/res.h b/display/res.h
index 5af8a26..90223ae 100644
--- a/display/res.h
+++ b/display/res.h
@@ -22,26 +22,32 @@
UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id);
-QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip);
+QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32 surface_id);
void PushDrawable(PDev *pdev, QXLDrawable *drawable);
+QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id);
+void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd);
-BOOL QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
- UINT8 **base_mem, UINT8 allocation_type);
+void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
+ UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
+void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type);
+void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type);
BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path);
BOOL QXLGetMask(PDev *pdev, QXLDrawable *drawable, SpiceQMask *qxl_mask, SURFOBJ *mask, POINTL *pos,
- BOOL invers, LONG width, LONG height);
+ BOOL invers, LONG width, LONG height, INT32 *surface_dest);
BOOL QXLGetBrush(PDev *pdev, QXLDrawable *drawable, SpiceBrush *qxl_brush,
- BRUSHOBJ *brush, POINTL *brush_pos);
+ BRUSHOBJ *brush, POINTL *brush_pos, INT32 *surface_dest,
+ SpiceRect *surface_rect);
BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
- SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache);
+ SpiceRect *area, XLATEOBJ *color_trans, UINT32 *hash_key, BOOL use_cache,
+ INT32 *surface_dest);
BOOL QXLGetBitsFromCache(PDev *pdev, QXLDrawable *drawable, UINT32 hash_key, QXLPHYSICAL *image_phys);
BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SURFOBJ *surf,
- SpiceRect *area);
+ SpiceRect *area, INT32 *surface_dest);
BOOL CheckIfCacheImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color_trans);
UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT32 size);
BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ *font, STROBJ *str);
-void UpdateArea(PDev *pdev, RECTL *area);
+void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id);
QXLCursorCmd *CursorCmd(PDev *pdev);
void PushCursorCmd(PDev *pdev, QXLCursorCmd *cursor_cmd);
diff --git a/display/rop.c b/display/rop.c
index 83efdd3..362eef4 100644
--- a/display/rop.c
+++ b/display/rop.c
@@ -20,6 +20,7 @@
#include "utils.h"
#include "res.h"
#include "rop.h"
+#include "surface.h"
enum ROP3type {
@@ -382,21 +383,28 @@ ROP3Info rops3[] = {
};
-static BOOL DoFill(PDev *pdev, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush, POINTL *brush_pos,
- ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask)
+static BOOL DoFill(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush,
+ POINTL *brush_pos, ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos,
+ BOOL invers_mask)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area && brush);
- if (!(drawable = Drawable(pdev, QXL_DRAW_FILL, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_FILL, area, clip, surface_id))) {
return FALSE;
}
- if (!QXLGetBrush(pdev, drawable, &drawable->u.fill.brush, brush, brush_pos) ||
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
+ if (!QXLGetBrush(pdev, drawable, &drawable->u.fill.brush, brush, brush_pos,
+ &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
!QXLGetMask(pdev, drawable, &drawable->u.fill.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top)) {
+ width, height, &drawable->surfaces_dest[1])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
@@ -405,28 +413,37 @@ static BOOL DoFill(PDev *pdev, RECTL *area, CLIPOBJ *clip, BRUSHOBJ *brush, POIN
drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+ }
+
PushDrawable(pdev, drawable);
return TRUE;
}
static BOOL GetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *bitmap_phys, SURFOBJ *surf,
- SpiceRect *area, XLATEOBJ *color_trans, BOOL use_cache)
+ SpiceRect *area, XLATEOBJ *color_trans, BOOL use_cache, INT32 *surface_dest)
{
DEBUG_PRINT((pdev, 9, "%s\n", __FUNCTION__));
if (surf->iType != STYPE_BITMAP) {
+ UINT32 surface_id;
+
ASSERT(pdev, (PDev *)surf->dhpdev == pdev);
- DEBUG_PRINT((pdev, 9, "%s copy from self\n", __FUNCTION__));
- *bitmap_phys = 0;
- drawable->self_bitmap = TRUE;
- drawable->self_bitmap_area = *area;
- area->right = area->right - area->left;
- area->left = 0;
- area->bottom = area->bottom - area->top;
- area->top = 0;
- return TRUE;
+ surface_id = GetSurfaceId(surf);
+ if (surface_id == drawable->surface_id) {
+ DEBUG_PRINT((pdev, 9, "%s copy from self\n", __FUNCTION__));
+ *bitmap_phys = 0;
+ drawable->self_bitmap = TRUE;
+ drawable->self_bitmap_area = *area;
+ area->right = area->right - area->left;
+ area->left = 0;
+ area->bottom = area->bottom - area->top;
+ area->top = 0;
+ return TRUE;
+ }
}
return QXLGetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, surf,
- area, color_trans, NULL, use_cache);
+ area, color_trans, NULL, use_cache, surface_dest);
}
static _inline UINT8 GdiScaleModeToQxl(ULONG scale_mode)
@@ -435,31 +452,44 @@ static _inline UINT8 GdiScaleModeToQxl(ULONG scale_mode)
SPICE_IMAGE_SCALE_MODE_NEAREST;
}
-static BOOL DoOpaque(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
- XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
+static BOOL DoOpaque(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+ RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
UINT16 rop_decriptor, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask,
ULONG scale_mode)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area && brush && src_rect && src);
- if (!(drawable = Drawable(pdev, QXL_DRAW_OPAQUE, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_OPAQUE, area, clip, surface_id))) {
return FALSE;
}
drawable->u.opaque.scale_mode = GdiScaleModeToQxl(scale_mode);
CopyRect(&drawable->u.opaque.src_area, src_rect);
- if (!QXLGetBrush(pdev, drawable, &drawable->u.opaque.brush, brush, brush_pos) ||
+
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
+ if (!QXLGetBrush(pdev, drawable, &drawable->u.opaque.brush, brush, brush_pos,
+ &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
!QXLGetMask(pdev, drawable, &drawable->u.opaque.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top) ||
+ width, height, &drawable->surfaces_dest[1]) ||
!GetBitmap(pdev, drawable, &drawable->u.opaque.src_bitmap, src,
- &drawable->u.opaque.src_area, color_trans, TRUE)) {
+ &drawable->u.opaque.src_area, color_trans, TRUE,
+ &drawable->surfaces_dest[2])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+ }
+ CopyRect(&drawable->surfaces_rects[2], src_rect);
+
drawable->u.opaque.rop_decriptor = rop_decriptor;
drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
PushDrawable(pdev, drawable);
@@ -574,19 +604,24 @@ static BOOL TestSplitClips(PDev *pdev, RECTL *src_rect, CLIPOBJ *clip, SURFOBJ *
return FALSE;
}
-static _inline BOOL DoPartialCopy(PDev *pdev, SURFOBJ *src, RECTL *src_rect, RECTL *area_rect,
- RECTL *clip_rect, XLATEOBJ *color_trans, ULONG scale_mode,
- UINT16 rop_decriptor)
+static _inline BOOL DoPartialCopy(PDev *pdev, UINT32 surface_id, SURFOBJ *src, RECTL *src_rect,
+ RECTL *area_rect, RECTL *clip_rect, XLATEOBJ *color_trans,
+ ULONG scale_mode, UINT16 rop_decriptor)
{
QXLDrawable *drawable;
RECTL clip_area;
+ UINT32 width;
+ UINT32 height;
SectRect(area_rect, clip_rect, &clip_area);
if (IsEmptyRect(&clip_area)) {
return TRUE;
}
- if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL))) {
+ width = clip_area.right - clip_area.left;
+ height = clip_area.bottom - clip_area.top;
+
+ if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, &clip_area, NULL, surface_id))) {
return FALSE;
}
@@ -603,24 +638,30 @@ static _inline BOOL DoPartialCopy(PDev *pdev, SURFOBJ *src, RECTL *src_rect, REC
clip_area.left;
if(!GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
- color_trans, FALSE)) {
+ color_trans, FALSE, &drawable->surfaces_dest[0])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ CopyRect(&drawable->surfaces_rects[0], src_rect);
PushDrawable(pdev, drawable);
return TRUE;
}
-static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
- XLATEOBJ *color_trans, UINT16 rop_decriptor, SURFOBJ *mask, POINTL *mask_pos,
- BOOL invers_mask, ULONG scale_mode)
+static BOOL DoCopy(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+ RECTL *src_rect, XLATEOBJ *color_trans, UINT16 rop_decriptor, SURFOBJ *mask,
+ POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
{
QXLDrawable *drawable;
BOOL use_cache;
+ UINT32 width;
+ UINT32 height;
ASSERT(pdev, pdev && area && src_rect && src);
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
if (mask) {
use_cache = TRUE;
} else {
@@ -629,10 +670,9 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
if (use_cache && TestSplitClips(pdev, src_rect, clip, mask) &&
!CheckIfCacheImage(pdev, src, color_trans)) {
-
if (clip->iDComplexity == DC_RECT) {
- if (!DoPartialCopy(pdev, src, src_rect, area, &clip->rclBounds, color_trans, scale_mode,
- rop_decriptor)) {
+ if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, &clip->rclBounds, color_trans,
+ scale_mode, rop_decriptor)) {
return FALSE;
}
} else {
@@ -649,8 +689,8 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
} buf;
more = CLIPOBJ_bEnum(clip, sizeof(buf), (ULONG *)&buf);
for(now = buf.rects, end = now + buf.count; now < end; now++) {
- if (!DoPartialCopy(pdev, src, src_rect, area, now, color_trans, scale_mode,
- rop_decriptor)) {
+ if (!DoPartialCopy(pdev, surface_id, src, src_rect, area, now, color_trans,
+ scale_mode, rop_decriptor)) {
return FALSE;
}
}
@@ -659,7 +699,7 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
return TRUE;
}
- if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_COPY, area, clip, surface_id))) {
return FALSE;
}
@@ -672,22 +712,29 @@ static BOOL DoCopy(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *
drawable->u.copy.scale_mode = GdiScaleModeToQxl(scale_mode);
CopyRect(&drawable->u.copy.src_area, src_rect);
if (!QXLGetMask(pdev, drawable, &drawable->u.copy.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top) ||
+ width, height, &drawable->surfaces_dest[0]) ||
!GetBitmap(pdev, drawable, &drawable->u.copy.src_bitmap, src, &drawable->u.copy.src_area,
- color_trans, use_cache)) {
+ color_trans, use_cache, &drawable->surfaces_dest[1])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+ CopyRect(&drawable->surfaces_rects[1], src_rect);
+
drawable->u.copy.rop_decriptor = rop_decriptor;
PushDrawable(pdev, drawable);
DEBUG_PRINT((pdev, 7, "%s: done\n", __FUNCTION__));
return TRUE;
}
-static BOOL DoCopyBits(PDev *pdev, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
+static BOOL DoCopyBits(PDev *pdev, UINT32 surface_id, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
ASSERT(pdev, pdev && area && src_pos);
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
@@ -697,144 +744,199 @@ static BOOL DoCopyBits(PDev *pdev, CLIPOBJ *clip, RECTL *area, POINTL *src_pos)
return TRUE;
}
- if (!(drawable = Drawable(pdev, QXL_COPY_BITS, area, clip))) {
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
+ if (!(drawable = Drawable(pdev, QXL_COPY_BITS, area, clip, surface_id))) {
return FALSE;
}
+
+ drawable->surfaces_dest[0] = surface_id;
+ CopyRectPoint(&drawable->surfaces_rects[0], src_pos, width, height);
+
CopyPoint(&drawable->u.copy_bits.src_pos, src_pos);
drawable->effect = QXL_EFFECT_OPAQUE;
PushDrawable(pdev, drawable);
return TRUE;
}
-static BOOL DoBlend(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
- XLATEOBJ *color_trans, ROP3Info *rop_info, SURFOBJ *mask, POINTL *mask_pos,
- BOOL invers_mask, ULONG scale_mode)
+static BOOL DoBlend(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+ RECTL *src_rect, XLATEOBJ *color_trans, ROP3Info *rop_info, SURFOBJ *mask,
+ POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area && src_rect && src);
- if (!(drawable = Drawable(pdev, QXL_DRAW_BLEND, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_BLEND, area, clip, surface_id))) {
return FALSE;
}
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
drawable->u.blend.scale_mode = GdiScaleModeToQxl(scale_mode);
CopyRect(&drawable->u.blend.src_area, src_rect);
if (!QXLGetMask(pdev, drawable, &drawable->u.blend.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top) ||
+ width, height, &drawable->surfaces_dest[0]) ||
!GetBitmap(pdev, drawable, &drawable->u.blend.src_bitmap, src, &drawable->u.blend.src_area,
- color_trans, TRUE)) {
+ color_trans, TRUE, &drawable->surfaces_dest[1])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+ CopyRect(&drawable->surfaces_rects[1], src_rect);
+
drawable->u.blend.rop_decriptor = rop_info->method_data;
drawable->effect = mask ? QXL_EFFECT_BLEND : rop_info->effect;
PushDrawable(pdev, drawable);
return TRUE;
}
-static BOOL DoBlackness(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, POINTL *mask_pos,
- BOOL invers_mask)
+static BOOL DoBlackness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask,
+ POINTL *mask_pos, BOOL invers_mask)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area);
- if (!(drawable = Drawable(pdev, QXL_DRAW_BLACKNESS, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_BLACKNESS, area, clip, surface_id))) {
return FALSE;
}
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
if (!QXLGetMask(pdev, drawable, &drawable->u.blackness.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top)) {
+ width, height, &drawable->surfaces_dest[0])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+
drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
PushDrawable(pdev, drawable);
return TRUE;
}
-static BOOL DoWhiteness(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, POINTL *mask_pos,
- BOOL invers_mask)
+static BOOL DoWhiteness(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask,
+ POINTL *mask_pos, BOOL invers_mask)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area);
- if (!(drawable = Drawable(pdev, QXL_DRAW_WHITENESS, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_WHITENESS, area, clip, surface_id))) {
return FALSE;
}
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
if (!QXLGetMask(pdev, drawable, &drawable->u.whiteness.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top)) {
+ width, height, &drawable->surfaces_dest[0])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+
drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_OPAQUE;
PushDrawable(pdev, drawable);
return TRUE;
}
-static BOOL DoInvers(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask, POINTL *mask_pos,
- BOOL invers_mask)
+static BOOL DoInvers(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *mask,
+ POINTL *mask_pos, BOOL invers_mask)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area);
- if (!(drawable = Drawable(pdev, QXL_DRAW_INVERS, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_INVERS, area, clip, surface_id))) {
return FALSE;
}
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
if (!QXLGetMask(pdev, drawable, &drawable->u.invers.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top)) {
+ width, height, &drawable->surfaces_dest[0])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[0], mask_pos, width, height);
+ }
+
drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_REVERT_ON_DUP;
PushDrawable(pdev, drawable);
return TRUE;
}
-static BOOL DoROP3(PDev *pdev, RECTL *area, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
- XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos, UINT8 rop3,
- SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+static BOOL DoROP3(PDev *pdev, UINT32 surface_id, RECTL *area, CLIPOBJ *clip, SURFOBJ *src,
+ RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos,
+ UINT8 rop3, SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
{
QXLDrawable *drawable;
+ UINT32 width;
+ UINT32 height;
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
ASSERT(pdev, pdev && area && brush && src_rect && src);
- if (!(drawable = Drawable(pdev, QXL_DRAW_ROP3, area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_ROP3, area, clip, surface_id))) {
return FALSE;
}
+ width = area->right - area->left;
+ height = area->bottom - area->top;
+
drawable->u.rop3.scale_mode = GdiScaleModeToQxl(scale_mode);
CopyRect(&drawable->u.rop3.src_area, src_rect);
- if (!QXLGetBrush(pdev, drawable, &drawable->u.rop3.brush, brush, brush_pos) ||
+ if (!QXLGetBrush(pdev, drawable, &drawable->u.rop3.brush, brush, brush_pos,
+ &drawable->surfaces_dest[0], &drawable->surfaces_rects[0]) ||
!QXLGetMask(pdev, drawable, &drawable->u.rop3.mask, mask, mask_pos, invers_mask,
- area->right - area->left, area->bottom - area->top) ||
+ width, height, &drawable->surfaces_dest[1]) ||
!GetBitmap(pdev, drawable, &drawable->u.rop3.src_bitmap, src, &drawable->u.rop3.src_area,
- color_trans, TRUE)) {
+ color_trans, TRUE, &drawable->surfaces_dest[2])) {
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
+ if (mask_pos) {
+ CopyRectPoint(&drawable->surfaces_rects[1], mask_pos, width, height);
+ }
+ CopyRect(&drawable->surfaces_rects[2], src_rect);
+
drawable->u.rop3.rop3 = rop3;
drawable->effect = mask ? QXL_EFFECT_BLEND : QXL_EFFECT_BLEND; //for now
PushDrawable(pdev, drawable);
return TRUE;
}
-static SURFOBJ *Copy16bppArea(PDev *pdev, RECTL *area)
+static SURFOBJ *Copy16bppArea(PDev *pdev, SURFOBJ *src, RECTL *area)
{
SIZEL size;
HSURF bitmap;
@@ -843,6 +945,9 @@ static SURFOBJ *Copy16bppArea(PDev *pdev, RECTL *area)
UINT8 *dest_end_line;
LONG src_stride;
UINT8 *src_line;
+ SurfaceInfo *surface;
+
+ surface = (SurfaceInfo *)src->dhsurf;
size.cx = area->right - area->left;
size.cy = area->bottom - area->top;
@@ -864,8 +969,9 @@ static SURFOBJ *Copy16bppArea(PDev *pdev, RECTL *area)
dest_line = surf_obj->pvScan0;
dest_end_line = dest_line + surf_obj->lDelta * surf_obj->sizlBitmap.cy;
- src_stride = pdev->draw_surf->lDelta;
- src_line = (UINT8 *)pdev->draw_surf->pvScan0 + area->top * src_stride + (area->left << 2);
+ src_stride = surface->draw_area.surf_obj->lDelta;
+ src_line = (UINT8 *)surface->draw_area.surf_obj->pvScan0 + area->top * src_stride +
+ (area->left << 2);
for (; dest_line != dest_end_line; dest_line += surf_obj->lDelta, src_line += src_stride) {
UINT16 *dest = (UINT16 *)dest_line;
@@ -885,13 +991,16 @@ error:
}
-static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
+static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *src, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *clip,
XLATEOBJ *color_trans, RECTL *dest_rect, POINTL src_pos,
POINTL *mask_pos, BRUSHOBJ *brush, POINTL *brush_pos, ROP4 rop4)
{
RECTL area;
SURFOBJ* surf_obj;
BOOL ret;
+ UINT32 surface_id;
+
+ surface_id = GetSurfaceId(src);
DEBUG_PRINT((pdev, 6, "%s\n", __FUNCTION__));
@@ -900,17 +1009,20 @@ static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *cli
area.left = MAX(0, src_pos.x);
area.right = MIN(src_pos.x + dest_rect->right - dest_rect->left, pdev->resolution.cx);
- UpdateArea(pdev, &area);
+ UpdateArea(pdev, &area, surface_id);
if (pdev->bitmap_format == BMF_16BPP) {
- surf_obj = Copy16bppArea(pdev, &area);
+ surf_obj = Copy16bppArea(pdev, src, &area);
if (!surf_obj) {
return FALSE;
}
src_pos.y = src_pos.y - area.top;
src_pos.x = src_pos.x - area.left;
} else {
- surf_obj = pdev->draw_surf;
+ SurfaceInfo *surface;
+
+ surface = (SurfaceInfo *)src->dhsurf;
+ surf_obj = surface->draw_area.surf_obj;
}
if (rop4 == 0xcccc) {
@@ -930,9 +1042,10 @@ static BOOL BitBltFromDev(PDev *pdev, SURFOBJ *dest, SURFOBJ *mask, CLIPOBJ *cli
return ret;
}
-BOOL _inline __DrvBitBlt(PDev *pdev, RECTL *dest_rect, CLIPOBJ *clip, SURFOBJ *src, RECTL *src_rect,
- XLATEOBJ *color_trans, BRUSHOBJ *brush, POINTL *brush_pos, ULONG rop3,
- SURFOBJ *mask, POINTL *mask_pos, BOOL invers_mask, ULONG scale_mode)
+BOOL _inline __DrvBitBlt(PDev *pdev, UINT32 surface_id, RECTL *dest_rect, CLIPOBJ *clip,
+ SURFOBJ *src, RECTL *src_rect, XLATEOBJ *color_trans, BRUSHOBJ *brush,
+ POINTL *brush_pos, ULONG rop3, SURFOBJ *mask, POINTL *mask_pos,
+ BOOL invers_mask, ULONG scale_mode)
{
ROP3Info *rop_info = &rops3[rop3];
@@ -940,26 +1053,27 @@ BOOL _inline __DrvBitBlt(PDev *pdev, RECTL *dest_rect, CLIPOBJ *clip, SURFOBJ *s
switch (rop_info->method_type) {
case ROP3_TYPE_FILL:
- return DoFill(pdev, dest_rect, clip, brush, brush_pos, rop_info, mask, mask_pos,
+ return DoFill(pdev, surface_id, dest_rect, clip, brush, brush_pos, rop_info, mask, mask_pos,
invers_mask);
case ROP3_TYPE_OPAQUE:
- return DoOpaque(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
- rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
+ return DoOpaque(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+ brush_pos, rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
case ROP3_TYPE_COPY:
- return DoCopy(pdev, dest_rect, clip, src, src_rect, color_trans, rop_info->method_data,
- mask, mask_pos, invers_mask, scale_mode);
+ return DoCopy(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans,
+ rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
case ROP3_TYPE_BLEND:
- return DoBlend(pdev, dest_rect, clip, src, src_rect, color_trans, rop_info, mask, mask_pos,
- invers_mask, scale_mode);
+ return DoBlend(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, rop_info,
+ mask, mask_pos, invers_mask, scale_mode);
case ROP3_TYPE_BLACKNESS:
- return DoBlackness(pdev, dest_rect, clip, mask, mask_pos, invers_mask);
+ return DoBlackness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
case ROP3_TYPE_WHITENESS:
- return DoWhiteness(pdev, dest_rect, clip, mask, mask_pos, invers_mask);
+ return DoWhiteness(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
case ROP3_TYPE_INVERS:
- return DoInvers(pdev, dest_rect, clip, mask, mask_pos, invers_mask);
+ return DoInvers(pdev, surface_id, dest_rect, clip, mask, mask_pos, invers_mask);
case ROP3_TYPE_ROP3:
- return DoROP3(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
- (UINT8)rop_info->method_data, mask, mask_pos, invers_mask, scale_mode);
+ return DoROP3(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+ brush_pos, (UINT8)rop_info->method_data, mask, mask_pos, invers_mask,
+ scale_mode);
case ROP3_TYPE_NOP:
return TRUE;
default:
@@ -1055,14 +1169,20 @@ static QXLRESULT BitBltCommon(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *
SURFOBJ *brush_mask = NULL;
#endif
QXLRESULT res;
+ UINT32 surface_id;
+
+ ASSERT(pdev, dest->iType != STYPE_BITMAP);
+
+ surface_id = GetSurfaceId(dest);
if (!PrepareBrush(brush)) {
return QXL_FAILED;
}
if ((rop3 = rop4 & 0xff) == (second_rop3 = ((rop4 >> 8) & 0xff))) {
- return __DrvBitBlt(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
- rop3, NULL, NULL, FALSE, scale_mode) ? QXL_SUCCESS : QXL_FAILED;
+ return __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+ brush_pos, rop3, NULL, NULL, FALSE, scale_mode) ? QXL_SUCCESS :
+ QXL_FAILED;
}
if (!mask) {
@@ -1080,15 +1200,17 @@ static QXLRESULT BitBltCommon(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *
}
DEBUG_PRINT((pdev, 5, "%s: mask, rop4 is 0x%x\n", __FUNCTION__, rop4));
ASSERT(pdev, mask_pos);
- res = (__DrvBitBlt(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos, rop3,
- mask, mask_pos, FALSE, scale_mode) &&
- __DrvBitBlt(pdev, dest_rect, clip, src, src_rect, color_trans, brush, brush_pos,
- second_rop3, mask, mask_pos, TRUE, scale_mode)) ? QXL_SUCCESS : QXL_FAILED;
+ res = (__DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+ brush_pos, rop3, mask, mask_pos, FALSE, scale_mode) &&
+ __DrvBitBlt(pdev, surface_id, dest_rect, clip, src, src_rect, color_trans, brush,
+ brush_pos, second_rop3, mask, mask_pos, TRUE, scale_mode)) ? QXL_SUCCESS :
+ QXL_FAILED;
#ifdef SUPPORT_BRUSH_AS_MASK
if (brush_mask) {
//free brush_mask;
}
#endif
+
return res;
}
@@ -1151,8 +1273,6 @@ static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask,
}
#endif
- ASSERT(pdev, dest->iType == STYPE_BITMAP || dest->hsurf == pdev->surf);
- ASSERT(pdev, !src || src->iType == STYPE_BITMAP || src->hsurf == pdev->surf);
ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
dest_rect->top < dest_rect->bottom);
@@ -1169,12 +1289,14 @@ static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask,
local_pos.y = src_pos->y + (area.top - dest_rect->top);
if (dest->iType == STYPE_BITMAP) {
- return BitBltFromDev(pdev, dest, mask, clip, color_trans, &area, local_pos, mask_pos,
- brush, brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
+ return BitBltFromDev(pdev, src, dest, mask, clip, color_trans, &area, local_pos,
+ mask_pos, brush, brush_pos, rop4) ? QXL_SUCCESS : QXL_FAILED;
}
- if (src->iType != STYPE_BITMAP && rop4 == 0xcccc) { //SRCCOPY no mask
- return DoCopyBits(pdev, clip, &area, &local_pos) ? QXL_SUCCESS : QXL_FAILED;
+ if (src->iType != STYPE_BITMAP
+ && GetSurfaceId(src) == GetSurfaceId(dest) && rop4 == 0xcccc) { //SRCCOPY no mask
+ return DoCopyBits(pdev, GetSurfaceId(src), clip, &area, &local_pos) ?
+ QXL_SUCCESS : QXL_FAILED;
}
src_rect.left = local_pos.x;
@@ -1185,6 +1307,7 @@ static QXLRESULT _BitBlt(PDev *pdev, SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask,
} else {
src_rect_ptr = NULL;
}
+
return BitBltCommon(pdev, dest, src, mask, clip, color_trans, &area, src_rect_ptr,
mask_pos, brush, brush_pos, rop4, COLORONCOLOR, NULL);
}
@@ -1197,14 +1320,13 @@ BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *cli
QXLRESULT res;
if (dest->iType == STYPE_BITMAP) {
- ASSERT(NULL, src && src->iType != STYPE_BITMAP && src->dhpdev && src_pos);
pdev = (PDev *)src->dhpdev;
} else {
- ASSERT(NULL, dest->dhpdev);
pdev = (PDev *)dest->dhpdev;
- CountCall(pdev, CALL_COUNTER_BIT_BLT);
}
+ CountCall(pdev, CALL_COUNTER_BIT_BLT);
+
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
if ((res = _BitBlt(pdev, dest, src, mask, clip, color_trans, dest_rect, src_pos, mask_pos,
brush, brush_pos, rop4))) {
@@ -1216,6 +1338,7 @@ BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *cli
return FALSE;
}
+
DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
return TRUE;
}
@@ -1226,14 +1349,13 @@ BOOL APIENTRY DrvCopyBits(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip,
PDev *pdev;
if (dest->iType == STYPE_BITMAP) {
- ASSERT(NULL, src && src->iType != STYPE_BITMAP && src->dhpdev && src_pos);
pdev = (PDev *)src->dhpdev;
} else {
- ASSERT(NULL, dest->dhpdev);
pdev = (PDev *)dest->dhpdev;
- CountCall(pdev, CALL_COUNTER_BIT_BLT);
}
+ CountCall(pdev, CALL_COUNTER_BIT_BLT);
+
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
return _BitBlt(pdev, dest, src, NULL, clip, color_trans, dest_rect, src_pos, NULL, NULL,
@@ -1389,13 +1511,12 @@ BOOL APIENTRY DrvStretchBltROP(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPO
PDev *pdev;
QXLRESULT res;
- if (!src || src->iType != STYPE_BITMAP) {
- ASSERT(NULL, src->dhpdev);
+ if (src && src->iType != STYPE_BITMAP) {
pdev = (PDev *)src->dhpdev;
- goto punt;
+ } else {
+ pdev = (PDev *)dest->dhpdev;
}
- ASSERT(NULL, dest && dest->iType != STYPE_BITMAP && dest->dhpdev);
pdev = (PDev *)dest->dhpdev;
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
CountCall(pdev, CALL_COUNTER_STRETCH_BLT_ROP);
@@ -1425,11 +1546,10 @@ BOOL APIENTRY DrvStretchBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ
ASSERT(NULL, src);
if (src->iType != STYPE_BITMAP) {
- ASSERT(NULL, src->dhpdev);
pdev = (PDev *)src->dhpdev;
- goto punt;
+ } else {
+ pdev = (PDev *)dest->dhpdev;
}
- ASSERT(NULL, dest && dest->iType != STYPE_BITMAP && dest->dhpdev);
pdev = (PDev *)dest->dhpdev;
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -1522,11 +1642,11 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
ASSERT(NULL, src && dest);
if (src->iType != STYPE_BITMAP) {
- ASSERT(NULL, src->dhpdev);
pdev = (PDev *)src->dhpdev;
- goto punt;
+ } else {
+ pdev = (PDev *)dest->dhpdev;
}
- ASSERT(NULL, dest->iType != STYPE_BITMAP && dest->dhpdev);
+
pdev = (PDev *)dest->dhpdev;
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -1562,7 +1682,7 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
return TRUE;
}
- if (!(drawable = Drawable(pdev, QXL_DRAW_ALPHA_BLEND, &area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_ALPHA_BLEND, &area, clip, GetSurfaceId(dest)))) {
DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
return FALSE;
}
@@ -1571,18 +1691,21 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
src_rect = &local_src;
}
+ CopyRect(&drawable->surfaces_rects[0], src_rect);
CopyRect(&drawable->u.alpha_blend.src_area, src_rect);
if (bland->BlendFunction.AlphaFormat == AC_SRC_ALPHA) {
ASSERT(pdev, src->iBitmapFormat == BMF_32BPP);
if (!QXLGetAlphaBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
- &drawable->u.alpha_blend.src_area)) {
+ &drawable->u.alpha_blend.src_area,
+ &drawable->surfaces_dest[0])) {
DEBUG_PRINT((pdev, 0, "%s: QXLGetAlphaBitmap failed\n", __FUNCTION__));
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
}
} else {
if (!QXLGetBitmap(pdev, drawable, &drawable->u.alpha_blend.src_bitmap, src,
- &drawable->u.alpha_blend.src_area, color_trans, NULL, TRUE)) {
+ &drawable->u.alpha_blend.src_area, color_trans, NULL, TRUE,
+ &drawable->surfaces_dest[0])) {
DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
@@ -1613,11 +1736,11 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
if (src->iType != STYPE_BITMAP) {
ASSERT(NULL, src->dhpdev);
pdev = (PDev *)src->dhpdev;
- goto punt;
+ } else {
+ ASSERT(NULL, dest->dhpdev);
+ pdev = (PDev *)dest->dhpdev;
}
- ASSERT(NULL, dest->iType != STYPE_BITMAP && dest->dhpdev);
- pdev = (PDev *)dest->dhpdev;
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
@@ -1643,7 +1766,7 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
return TRUE;
}
- if (!(drawable = Drawable(pdev, QXL_DRAW_TRANSPARENT, &area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_TRANSPARENT, &area, clip, GetSurfaceId(dest)))) {
DEBUG_PRINT((pdev, 0, "%s: Drawable failed\n", __FUNCTION__));
return FALSE;
}
@@ -1653,8 +1776,10 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
}
CopyRect(&drawable->u.transparent.src_area, src_rect);
+ CopyRect(&drawable->surfaces_rects[0], src_rect);
if (!QXLGetBitmap(pdev, drawable, &drawable->u.transparent.src_bitmap, src,
- &drawable->u.transparent.src_area, color_trans, NULL, TRUE)) {
+ &drawable->u.transparent.src_area, color_trans, NULL, TRUE,
+ &drawable->surfaces_dest[0])) {
DEBUG_PRINT((pdev, 0, "%s: QXLGetBitmap failed\n", __FUNCTION__));
ReleaseOutput(pdev, drawable->release_info.id);
return FALSE;
diff --git a/display/sources b/display/sources
index 6c1d5c7..617f42c 100644
--- a/display/sources
+++ b/display/sources
@@ -30,5 +30,6 @@ SOURCES=driver.c \
mspace.c \
quic.c \
surface.c \
+ dd.c \
driver.rc
diff --git a/display/surface.c b/display/surface.c
index 36ae44c..f15255a 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -36,14 +36,18 @@
#include "res.h"
#include "surface.h"
-BOOL CreateDrawArea(PDev *pdev, DrawArea *drawarea, UINT8 *base_mem, UINT32 cx, UINT32 cy)
+BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, UINT32 cx, UINT32 cy, UINT32 stride,
+ UINT32 surface_id)
{
SIZEL size;
+ DrawArea *drawarea;
size.cx = cx;
size.cy = cy;
- if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, size.cx << 2, BMF_32BPP, 0, base_mem))) {
+ drawarea = &pdev->surfaces_info[surface_id].draw_area;
+
+ if (!(drawarea->bitmap = (HSURF)EngCreateBitmap(size, stride, BMF_32BPP, 0, base_mem))) {
DEBUG_PRINT((pdev, 0, "%s: EngCreateBitmap failed\n", __FUNCTION__));
return FALSE;
}
@@ -58,6 +62,8 @@ BOOL CreateDrawArea(PDev *pdev, DrawArea *drawarea, UINT8 *base_mem, UINT32 cx,
goto error;
}
+ drawarea->base_mem = base_mem;
+
return TRUE;
error:
EngDeleteSurface(drawarea->bitmap);
@@ -66,15 +72,19 @@ error:
VOID FreeDrawArea(DrawArea *drawarea)
{
- EngUnlockSurface(drawarea->surf_obj);
- EngDeleteSurface(drawarea->bitmap);
+ if (drawarea->surf_obj) {
+ EngUnlockSurface(drawarea->surf_obj);
+ EngDeleteSurface(drawarea->bitmap);
+ drawarea->surf_obj = NULL;
+ }
}
HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
- UINT8 **base_mem, UINT8 allocation_type)
+ UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
{
UINT8 depth;
HBITMAP surf;
+ UINT32 stride;
switch (format) {
case BMF_8BPP:
@@ -93,7 +103,7 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
return 0;
};
- if (!(surf = EngCreateDeviceBitmap((DHSURF)pdev, size, format))) {
+ if (!(surf = EngCreateDeviceBitmap((DHSURF)&pdev->surfaces_info[surface_id], size, format))) {
DEBUG_PRINT((NULL, 0, "%s: create device surface failed, 0x%lx\n",
__FUNCTION__, pdev));
goto out_error1;
@@ -104,26 +114,61 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
HOOK_STRETCHBLTROP | HOOK_TRANSPARENTBLT | HOOK_ALPHABLEND
#ifdef CALL_TEST
| HOOK_PLGBLT | HOOK_FILLPATH | HOOK_STROKEANDFILLPATH | HOOK_LINETO |
- HOOK_GRADIENTFILL
+ HOOK_GRADIENTFILL
#endif
)) {
DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
goto out_error2;
}
- if (!QXLGetSurface(pdev, phys_mem, size.cx, size.cy, 32, base_mem, allocation_type)) {
+ pdev->surfaces_info[surface_id].pdev = pdev;
+
+ QXLGetSurface(pdev, phys_mem, size.cx, size.cy, depth, &stride, base_mem, allocation_type);
+ if (!*base_mem) {
goto out_error2;
}
+ if (!CreateDrawArea(pdev, *base_mem, size.cx, size.cy, stride, surface_id)) {
+ goto out_error3;
+ }
+
+ if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
+ QXLSurfaceCmd *surface;
+
+ surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
+ surface->u.surface_create.depth = depth;
+ surface->u.surface_create.width = size.cx;
+ surface->u.surface_create.height = size.cy;
+ surface->u.surface_create.stride = -(INT32)stride;
+ surface->u.surface_create.data = *phys_mem;
+ PushSurfaceCmd(pdev, surface);
+ }
+
return surf;
+out_error3:
+ QXLDelSurface(pdev, *base_mem, allocation_type);
out_error2:
+ FreeSurface(pdev, surface_id);
EngDeleteSurface((HSURF)surf);
out_error1:
return 0;
}
-VOID DeleteDeviceBitmap(HSURF surf)
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
{
- EngDeleteSurface(surf);
+ DrawArea *drawarea;
+
+ drawarea = &pdev->surfaces_info[surface_id].draw_area;
+
+ FreeDrawArea(drawarea);
+
+ if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0 &&
+ pdev->Res.surfaces_used[surface_id]) {
+ QXLSurfaceCmd *surface;
+
+ surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
+ QXLGetDelSurface(pdev, surface, surface_id, allocation_type);
+ PushSurfaceCmd(pdev, surface);
+ }
}
diff --git a/display/surface.h b/display/surface.h
index a384020..e0ecc57 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -1,20 +1,54 @@
#ifndef SURFACE_H
#define SURFACE_H
+#include "qxldd.h"
+
+static _inline UINT32 GetSurfaceId(SURFOBJ *surf)
+{
+ PDev *pdev;
+ SurfaceInfo *surface;
+ UINT32 surface_id;
+
+ pdev = (PDev *)surf->dhpdev;
+
+ surface = (SurfaceInfo *)surf->dhsurf;
+ surface_id = surface - pdev->surfaces_info;
+ return surface_id;
+}
+
+static _inline void FreeSurface(PDev *pdev, UINT32 surface_id)
+{
+ pdev->Res.surfaces_used[surface_id] = 0;
+}
+
+
+static UINT32 GetFreeSurface(PDev *pdev)
+{
+ UINT32 x;
+
+ //not effective, fix me
+ for (x = 1; x < pdev->n_surfaces; ++x) {
+ if (!pdev->Res.surfaces_used[x]) {
+ pdev->Res.surfaces_used[x] = 1;
+ return x;
+ }
+ }
+
+ return 0;
+}
+
enum {
DEVICE_BITMAP_ALLOCATION_TYPE_SURF0,
+ DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM,
+ DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
};
-typedef struct DrawArea {
- HSURF bitmap;
- SURFOBJ* surf_obj;
-} DrawArea;
-
-BOOL CreateDrawArea(PDev *pdev, DrawArea *drawarea, UINT8 *base_mem, UINT32 cx, UINT32 cy);
+BOOL CreateDrawArea(PDev *pdev, UINT8 *base_mem, UINT32 cx, UINT32 cy, UINT32 stride,
+ UINT32 surface_id);
VOID FreeDrawArea(DrawArea *drawarea);
HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
- UINT8 **base_mem, UINT8 allocation_type);
-VOID DeleteDeviceBitmap(HSURF surf);
+ UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type);
+VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type);
#endif
diff --git a/display/text.c b/display/text.c
index c661544..9d04472 100644
--- a/display/text.c
+++ b/display/text.c
@@ -20,6 +20,7 @@
#include "utils.h"
#include "res.h"
#include "rop.h"
+#include "surface.h"
BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *clip,
RECTL *ignored, RECTL *opaque_rect,
@@ -31,12 +32,15 @@ BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *cli
ROP3Info *back_rop;
PDev* pdev;
RECTL area;
+ UINT32 surface_id;
if (!(pdev = (PDev *)surf->dhpdev)) {
DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
return FALSE;
}
+ surface_id = GetSurfaceId(surf);
+
CountCall(pdev, CALL_COUNTER_TEXT_OUT);
DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -62,13 +66,14 @@ BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *cli
}
}
- if (!(drawable = Drawable(pdev, QXL_DRAW_TEXT, &area, clip))) {
+ if (!(drawable = Drawable(pdev, QXL_DRAW_TEXT, &area, clip, surface_id))) {
return FALSE;
}
if (opaque_rect) {
ASSERT(pdev, back_brash && brushs_origin);
- if (!QXLGetBrush(pdev, drawable, &drawable->u.text.back_brush, back_brash, brushs_origin)) {
+ if (!QXLGetBrush(pdev, drawable, &drawable->u.text.back_brush, back_brash, brushs_origin,
+ &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
goto error;
}
CopyRect(&drawable->u.text.back_area, &area);
@@ -87,7 +92,8 @@ BOOL APIENTRY DrvTextOut(SURFOBJ *surf, STROBJ *str, FONTOBJ *font, CLIPOBJ *cli
if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
} else if (!QXLGetBrush(pdev, drawable, &drawable->u.text.fore_brush, fore_brush,
- brushs_origin)) {
+ brushs_origin, &drawable->surfaces_dest[1],
+ &drawable->surfaces_rects[1])) {
DEBUG_PRINT((pdev, 0, "%s: get brush failed\n", __FUNCTION__));
goto error;
}
diff --git a/display/utils.h b/display/utils.h
index 74f3476..124aff7 100644
--- a/display/utils.h
+++ b/display/utils.h
@@ -46,6 +46,12 @@ static _inline LONG RectSize(RECTL *rect)
return (rect->right - rect->left) * (rect->bottom - rect->top);
}
+#define CopyRectPoint(dest, src, width, height) \
+ (dest)->left = (src)->x; \
+ (dest)->right = (src)->x + width; \
+ (dest)->top = (src)->y; \
+ (dest)->bottom = (src)->y + height;
+
#define SameRect(r1, r2) ((r1)->left == (r2)->left && (r1)->right == (r2)->right && \
(r1)->top == (r2)->top && (r1)->bottom == (r2)->bottom)
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index 12f5aac..566648c 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -66,6 +66,7 @@ typedef struct QXLDriverInfo {
UINT32 update_area_port;
SpiceRect *update_area;
+ UINT32 *update_surface;
UINT32 *mm_clock;
@@ -79,15 +80,25 @@ typedef struct QXLDriverInfo {
UINT8 main_mem_slot_id;
UINT8 slot_id_bits;
UINT8 slot_gen_bits;
+ UINT8 *slots_generation;
+ UINT64 *ram_slot_start;
+ UINT64 *ram_slot_end;
MemSlot main_mem_slot;
UINT32 destroy_surface_wait_port;
UINT32 create_primary_port;
UINT32 destroy_primary_port;
+ UINT32 memslot_add_port;
+ UINT32 memslot_del_port;
+ UINT32 destroy_all_surfaces_port;
UINT32 dev_id;
QXLSurfaceCreate *primary_surface_create;
+
+ UINT32 n_surfaces;
+
+ UINT64 fb_phys;
} QXLDriverInfo;
diff --git a/miniport/qxl.c b/miniport/qxl.c
index fe5449c..9c7e1bc 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -946,6 +946,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
+
driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
driver_info->log_buf = dev_ext->ram_header->log_buf;
@@ -957,6 +958,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
driver_info->log_level = &dev_ext->rom->log_level;
driver_info->update_area_port = dev_ext->io_port + QXL_IO_UPDATE_AREA;
driver_info->update_area = &dev_ext->ram_header->update_area;
+ driver_info->update_surface = &dev_ext->ram_header->update_surface;
driver_info->num_pages = dev_ext->rom->num_pages;
driver_info->io_pages_virt = dev_ext->ram_start + driver_info->surface0_area_size;
@@ -967,17 +969,27 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
driver_info->num_mem_slot = dev_ext->rom->slots_end;
driver_info->slot_gen_bits = dev_ext->rom->slot_gen_bits;
driver_info->slot_id_bits = dev_ext->rom->slot_id_bits;
+ driver_info->slots_generation = &dev_ext->rom->slot_generation;
+ driver_info->ram_slot_start = &dev_ext->ram_header->mem_slot.mem_start;
+ driver_info->ram_slot_end = &dev_ext->ram_header->mem_slot.mem_end;
driver_info->main_mem_slot = dev_ext->mem_slots[driver_info->main_mem_slot_id];
#if (WINVER < 0x0501)
driver_info->WaitForEvent = QXLWaitForEvent;
#endif
driver_info->destroy_surface_wait_port = dev_ext->io_port + QXL_IO_DESTROY_SURFACE_WAIT;
+ driver_info->destroy_all_surfaces_port = dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES;
driver_info->create_primary_port = dev_ext->io_port + QXL_IO_CREATE_PRIMARY;
driver_info->destroy_primary_port = dev_ext->io_port + QXL_IO_DESTROY_PRIMARY;
+ driver_info->memslot_add_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD;
+ driver_info->memslot_del_port = dev_ext->io_port + QXL_IO_MEMSLOT_DEL;
driver_info->primary_surface_create = &dev_ext->ram_header->create_surface;
+ driver_info->n_surfaces = dev_ext->rom->n_surfaces;
+
+ driver_info->fb_phys = dev_ext->vram_physical.QuadPart;
+
driver_info->dev_id = dev_ext->rom->id;
}
break;
commit b53df9ae9e1384a412702df9a371fba6cd3cd29e
Author: Izik Eidus <ieidus at redhat.com>
Date: Wed Mar 31 01:46:38 2010 +0300
spice-protocol off screens supports
Signed-off-by: Izik Eidus <ieidus at redhat.com>
diff --git a/spice/draw.h b/spice/draw.h
index 254e0b0..075324b 100644
--- a/spice/draw.h
+++ b/spice/draw.h
@@ -155,6 +155,7 @@ enum {
SPICE_IMAGE_TYPE_LZ_RGB,
SPICE_IMAGE_TYPE_GLZ_RGB,
SPICE_IMAGE_TYPE_FROM_CACHE,
+ SPICE_IMAGE_TYPE_SURFACE,
};
enum {
@@ -203,6 +204,15 @@ typedef struct SPICE_ATTR_PACKED SpiceBitmapImage {
SpiceBitmap bitmap;
} SpiceBitmapImage;
+typedef struct SPICE_ATTR_PACKED SpiceSurface {
+ uint32_t surface_id;
+} SpiceSurface;
+
+typedef struct SPICE_ATTR_PACKED SpiceSurfaceImage {
+ SpiceImageDescriptor descriptor; //?
+ SpiceSurface surface;
+} SpiceSurfaceImage;
+
typedef struct SPICE_ATTR_PACKED SpiceQUICData {
uint32_t data_size;
uint8_t data[0];
diff --git a/spice/qxl_dev.h b/spice/qxl_dev.h
index 353018d..af9f30a 100644
--- a/spice/qxl_dev.h
+++ b/spice/qxl_dev.h
@@ -70,6 +70,7 @@ enum {
QXL_IO_CREATE_PRIMARY,
QXL_IO_DESTROY_PRIMARY,
QXL_IO_DESTROY_SURFACE_WAIT,
+ QXL_IO_DESTROY_ALL_SURFACES,
QXL_IO_RANGE_SIZE
};
@@ -91,6 +92,7 @@ typedef struct SPICE_ATTR_PACKED QXLRom {
uint8_t slot_gen_bits;
uint8_t slot_id_bits;
uint8_t slot_generation;
+ uint32_t n_surfaces;
} QXLRom;
typedef struct SPICE_ATTR_PACKED QXLMode {
@@ -118,6 +120,7 @@ enum QXLCmdType {
QXL_CMD_UPDATE,
QXL_CMD_CURSOR,
QXL_CMD_MESSAGE,
+ QXL_CMD_SURFACE,
};
typedef struct SPICE_ATTR_PACKED QXLCommand {
@@ -169,6 +172,7 @@ typedef struct SPICE_ATTR_PACKED QXLRam {
QXLCursorRing cursor_ring;
QXLReleaseRing release_ring;
SpiceRect update_area;
+ uint32_t update_surface;
QXLMemSlot mem_slot;
QXLSurfaceCreate create_surface;
uint64_t flags;
@@ -200,6 +204,7 @@ typedef struct SPICE_ATTR_PACKED QXLUpdateCmd {
QXLReleaseInfo release_info;
SpiceRect area;
uint32_t update_id;
+ uint32_t surface_id;
} QXLUpdateCmd;
typedef struct SPICE_ATTR_PACKED QXLCursor {
@@ -274,6 +279,7 @@ typedef struct SPICE_ATTR_PACKED QXLCopyBits {
typedef struct SPICE_ATTR_PACKED QXLDrawable {
QXLReleaseInfo release_info;
+ uint32_t surface_id;
uint8_t effect;
uint8_t type;
uint8_t self_bitmap;
@@ -281,6 +287,8 @@ typedef struct SPICE_ATTR_PACKED QXLDrawable {
SpiceRect bbox;
SpiceClip clip;
uint32_t mm_time;
+ int32_t surfaces_dest[3];
+ SpiceRect surfaces_rects[3];
union {
SpiceFill fill;
SpiceOpaque opaque;
@@ -298,6 +306,29 @@ typedef struct SPICE_ATTR_PACKED QXLDrawable {
} u;
} QXLDrawable;
+enum QXLSurfaceCmdType {
+ QXL_SURFACE_CMD_CREATE,
+ QXL_SURFACE_CMD_DESTROY,
+};
+
+typedef struct SPICE_ATTR_PACKED QXLSurface {
+ uint8_t depth;
+ uint32_t width;
+ uint32_t height;
+ int32_t stride;
+ QXLPHYSICAL data;
+} QXLSurface;
+
+typedef struct SPICE_ATTR_PACKED QXLSurfaceCmd {
+ QXLReleaseInfo release_info;
+ uint32_t surface_id;
+ uint8_t type;
+ uint32_t flags;
+ union {
+ QXLSurface surface_create;
+ } u;
+} QXLSurfaceCmd;
+
typedef struct SPICE_ATTR_PACKED QXLClipRects {
uint32_t num_rects;
QXLDataChunk chunk;
@@ -349,6 +380,7 @@ typedef struct SPICE_ATTR_PACKED QXLImage {
union { // variable length
SpiceBitmap bitmap;
SpiceQUICData quic;
+ SpiceSurface surface_image;
};
} QXLImage;
More information about the Spice-devel
mailing list