summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-09-23 21:58:35 +0200
committerMarc-André Lureau <marcandre.lureau@gmail.com>2013-09-30 02:19:51 +0200
commitc2b1c0e7f33186a7167e6666cd5dbd0ddeb2562e (patch)
tree9980561b9bd7fba37cdc5fa2aff99c780bdbd0b5 /client
parentc3d6f0e1df482f207d0c061465361853c444aad8 (diff)
downloadspice-c2b1c0e7f33186a7167e6666cd5dbd0ddeb2562e.tar.gz
spice-c2b1c0e7f33186a7167e6666cd5dbd0ddeb2562e.tar.xz
spice-c2b1c0e7f33186a7167e6666cd5dbd0ddeb2562e.zip
spicec: add sw canvas diff check
Setting CHECKDIFF=1 environment variable will compare the rendering of the selected canvas with a software canvas. This is useful for debugging some rendering issues, however it is far from being perfect, since it's not able to tell whether one or the other is actually faulty. It's a strong indication though of which operations are incorrect. Ideally, all operations should be checked, however, a few of them are disabled by default because they fail all the time, and it looks like pixman is not very accurate for blending/compositing (at least visually, it seems gl has better rendering)
Diffstat (limited to 'client')
-rw-r--r--client/display_channel.cpp88
-rw-r--r--client/display_channel.h2
-rw-r--r--client/red_pixmap.h19
-rw-r--r--client/utils.h3
4 files changed, 88 insertions, 24 deletions
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 9ba93c48..47076ad9 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -611,6 +611,7 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
#endif
, _interrupt_update (*this)
, _mig_wait_primary (false)
+ , _check_diff (getenv("CHECKDIFF") != NULL)
{
DisplayHandler* handler = static_cast<DisplayHandler*>(get_message_handler());
@@ -1280,6 +1281,22 @@ void DisplayChannel::create_canvas(int surface_id, const std::vector<int>& canva
// make sure to refresh the whole display
SpiceRect rect = { 0, 0, width, height };
invalidate(rect, true);
+
+ try {
+ if (!_check_diff)
+ return;
+
+ SCanvas *canvas = new SCanvas(surface_id == 0, width, height, format,
+ screen()->get_window(),
+ _pixmap_cache, _palette_cache, _glz_window,
+ _surfaces_cache);
+ _swsurfaces_cache[surface_id] = canvas;
+ if (surface_id == 0) {
+ LOG_INFO("display %d: check sw", get_id());
+ }
+ } catch (...) {
+ spice_warn_if_reached();
+ }
}
void DisplayChannel::handle_mode(RedPeer::InMessage* message)
@@ -1624,29 +1641,52 @@ void DisplayChannel::handle_surface_destroy(RedPeer::InMessage* message)
}
}
-#define PRE_DRAW
-#define POST_DRAW
+#define DRAW(type, can_diff) { \
+ canvas->draw_##type(*type, message->size()); \
+ if (type->base.surface_id == 0) { \
+ invalidate(type->base.box, false); \
+ } \
+ if ((can_diff) && _check_diff) { \
+ Canvas *swcanvas = _swsurfaces_cache[type->base.surface_id]; \
+ swcanvas->draw_##type(*type, message->size()); \
+ check_diff(swcanvas, canvas, type->base.box); \
+ } \
+}
+
+#include "red_pixmap_sw.h"
+
+void check_diff(Canvas *a, Canvas *b, const SpiceRect& rect)
+{
+ QRegion region;
+ RedPixmapSw *ap = new RedPixmapSw(rect.right, rect.bottom, RedDrawable::RGB32, true, 0);
+ RedPixmapSw *bp = new RedPixmapSw(rect.right, rect.bottom, RedDrawable::RGB32, true, 0);
+
+ region_init(&region);
+ region_add(&region, &rect);
+ a->copy_pixels(region, *ap);
+ b->copy_pixels(region, *bp);
+ ap->equal(*bp, rect);
-#define DRAW(type) { \
- PRE_DRAW; \
- canvas->draw_##type(*type, message->size()); \
- POST_DRAW; \
- if (type->base.surface_id == 0) { \
- invalidate(type->base.box, false); \
- } \
+ delete ap;
+ delete bp;
}
void DisplayChannel::handle_copy_bits(RedPeer::InMessage* message)
{
Canvas *canvas;
SpiceMsgDisplayCopyBits* copy_bits = (SpiceMsgDisplayCopyBits*)message->data();
- PRE_DRAW;
canvas = _surfaces_cache[copy_bits->base.surface_id];
+ Canvas *swcanvas = _swsurfaces_cache[copy_bits->base.surface_id];
+
canvas->copy_bits(*copy_bits, message->size());
- POST_DRAW;
if (copy_bits->base.surface_id == 0) {
invalidate(copy_bits->base.box, false);
}
+
+ if (_check_diff) {
+ swcanvas->copy_bits(*copy_bits, message->size());
+ check_diff(swcanvas, canvas, copy_bits->base.box);
+ }
}
void DisplayChannel::handle_draw_fill(RedPeer::InMessage* message)
@@ -1654,7 +1694,7 @@ void DisplayChannel::handle_draw_fill(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawFill* fill = (SpiceMsgDisplayDrawFill*)message->data();
canvas = _surfaces_cache[fill->base.surface_id];
- DRAW(fill);
+ DRAW(fill, FALSE);
}
void DisplayChannel::handle_draw_opaque(RedPeer::InMessage* message)
@@ -1662,7 +1702,7 @@ void DisplayChannel::handle_draw_opaque(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawOpaque* opaque = (SpiceMsgDisplayDrawOpaque*)message->data();
canvas = _surfaces_cache[opaque->base.surface_id];
- DRAW(opaque);
+ DRAW(opaque, TRUE);
}
void DisplayChannel::handle_draw_copy(RedPeer::InMessage* message)
@@ -1670,7 +1710,7 @@ void DisplayChannel::handle_draw_copy(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawCopy* copy = (SpiceMsgDisplayDrawCopy*)message->data();
canvas = _surfaces_cache[copy->base.surface_id];
- DRAW(copy);
+ DRAW(copy, TRUE);
}
void DisplayChannel::handle_draw_blend(RedPeer::InMessage* message)
@@ -1678,7 +1718,7 @@ void DisplayChannel::handle_draw_blend(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawBlend* blend = (SpiceMsgDisplayDrawBlend*)message->data();
canvas = _surfaces_cache[blend->base.surface_id];
- DRAW(blend);
+ DRAW(blend, TRUE);
}
void DisplayChannel::handle_draw_blackness(RedPeer::InMessage* message)
@@ -1686,7 +1726,7 @@ void DisplayChannel::handle_draw_blackness(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawBlackness* blackness = (SpiceMsgDisplayDrawBlackness*)message->data();
canvas = _surfaces_cache[blackness->base.surface_id];
- DRAW(blackness);
+ DRAW(blackness, TRUE);
}
void DisplayChannel::handle_draw_whiteness(RedPeer::InMessage* message)
@@ -1694,7 +1734,7 @@ void DisplayChannel::handle_draw_whiteness(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawWhiteness* whiteness = (SpiceMsgDisplayDrawWhiteness*)message->data();
canvas = _surfaces_cache[whiteness->base.surface_id];
- DRAW(whiteness);
+ DRAW(whiteness, TRUE);
}
void DisplayChannel::handle_draw_invers(RedPeer::InMessage* message)
@@ -1702,7 +1742,7 @@ void DisplayChannel::handle_draw_invers(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawInvers* invers = (SpiceMsgDisplayDrawInvers*)message->data();
canvas = _surfaces_cache[invers->base.surface_id];
- DRAW(invers);
+ DRAW(invers, TRUE);
}
void DisplayChannel::handle_draw_rop3(RedPeer::InMessage* message)
@@ -1710,7 +1750,7 @@ void DisplayChannel::handle_draw_rop3(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawRop3* rop3 = (SpiceMsgDisplayDrawRop3*)message->data();
canvas = _surfaces_cache[rop3->base.surface_id];
- DRAW(rop3);
+ DRAW(rop3, TRUE);
}
void DisplayChannel::handle_draw_stroke(RedPeer::InMessage* message)
@@ -1718,7 +1758,7 @@ void DisplayChannel::handle_draw_stroke(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawStroke* stroke = (SpiceMsgDisplayDrawStroke*)message->data();
canvas = _surfaces_cache[stroke->base.surface_id];
- DRAW(stroke);
+ DRAW(stroke, TRUE);
}
void DisplayChannel::handle_draw_text(RedPeer::InMessage* message)
@@ -1726,7 +1766,7 @@ void DisplayChannel::handle_draw_text(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawText* text = (SpiceMsgDisplayDrawText*)message->data();
canvas = _surfaces_cache[text->base.surface_id];
- DRAW(text);
+ DRAW(text, FALSE);
}
void DisplayChannel::handle_draw_transparent(RedPeer::InMessage* message)
@@ -1734,7 +1774,7 @@ void DisplayChannel::handle_draw_transparent(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawTransparent* transparent = (SpiceMsgDisplayDrawTransparent*)message->data();
canvas = _surfaces_cache[transparent->base.surface_id];
- DRAW(transparent);
+ DRAW(transparent, TRUE);
}
void DisplayChannel::handle_draw_alpha_blend(RedPeer::InMessage* message)
@@ -1742,7 +1782,7 @@ void DisplayChannel::handle_draw_alpha_blend(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawAlphaBlend* alpha_blend = (SpiceMsgDisplayDrawAlphaBlend*)message->data();
canvas = _surfaces_cache[alpha_blend->base.surface_id];
- DRAW(alpha_blend);
+ DRAW(alpha_blend, FALSE);
}
void DisplayChannel::handle_draw_composite(RedPeer::InMessage* message)
@@ -1750,7 +1790,7 @@ void DisplayChannel::handle_draw_composite(RedPeer::InMessage* message)
Canvas *canvas;
SpiceMsgDisplayDrawComposite* composite = (SpiceMsgDisplayDrawComposite*)message->data();
canvas = _surfaces_cache[composite->base.surface_id];
- DRAW(composite);
+ DRAW(composite, TRUE);
}
void DisplayChannel::streams_time()
diff --git a/client/display_channel.h b/client/display_channel.h
index 197ae73a..8a302896 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -187,6 +187,7 @@ private:
private:
SurfacesCache _surfaces_cache;
+ SurfacesCache _swsurfaces_cache;
PixmapCache& _pixmap_cache;
PaletteCache _palette_cache;
GlzDecoderWindow& _glz_window;
@@ -226,6 +227,7 @@ private:
InterruptUpdate _interrupt_update;
bool _mig_wait_primary;
+ bool _check_diff;
friend class SetModeEvent;
friend class CreatePrimarySurfaceEvent;
friend class DestroyPrimarySurfaceEvent;
diff --git a/client/red_pixmap.h b/client/red_pixmap.h
index 240ed768..3f12855e 100644
--- a/client/red_pixmap.h
+++ b/client/red_pixmap.h
@@ -36,6 +36,25 @@ public:
bool is_big_endian_bits();
virtual RedDrawable::Format get_format() { return _format; }
+ bool equal(const RedPixmap &other, const SpiceRect &rect) const {
+ spice_debug("l:%d r:%d t:%d b:%d", rect.left, rect.right, rect.top, rect.bottom);
+ for (int x = rect.left; x < rect.right; ++x)
+ for (int y = rect.top; y < rect.bottom; ++y) {
+ for (int i = 0; i < 3; i++) { // ignore alpha
+ int p = x * 4 + y * _stride + i;
+ if (other._data[p] != _data[p]) {
+ spice_printerr("equal fails at (+%d+%d) +%d+%d:%d in %dx%d",
+ rect.left, rect.top, x-rect.left, y-rect.top, i,
+ _width-rect.left, _height-rect.top);
+ if (getenv("DIFFBP"))
+ SPICE_BREAKPOINT();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
protected:
Format _format;
int _width;
diff --git a/client/utils.h b/client/utils.h
index 46572795..d8d69626 100644
--- a/client/utils.h
+++ b/client/utils.h
@@ -50,6 +50,9 @@ private:
throw Exception(exption_string, err); \
}
+#define SPICE_BREAKPOINT() do{ \
+ __asm__ __volatile__ ("int $03"); \
+}while(0)
template <class T>
class AutoRef {