qxl-logger.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * qxl command logging -- for debug purposes
  3. *
  4. * Copyright (C) 2010 Red Hat, Inc.
  5. *
  6. * maintained by Gerd Hoffmann <kraxel@redhat.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 or
  11. * (at your option) version 3 of the License.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "qemu/osdep.h"
  22. #include "qemu/timer.h"
  23. #include "qxl.h"
  24. static const char *const qxl_type[] = {
  25. [ QXL_CMD_NOP ] = "nop",
  26. [ QXL_CMD_DRAW ] = "draw",
  27. [ QXL_CMD_UPDATE ] = "update",
  28. [ QXL_CMD_CURSOR ] = "cursor",
  29. [ QXL_CMD_MESSAGE ] = "message",
  30. [ QXL_CMD_SURFACE ] = "surface",
  31. };
  32. static const char *const qxl_draw_type[] = {
  33. [ QXL_DRAW_NOP ] = "nop",
  34. [ QXL_DRAW_FILL ] = "fill",
  35. [ QXL_DRAW_OPAQUE ] = "opaque",
  36. [ QXL_DRAW_COPY ] = "copy",
  37. [ QXL_COPY_BITS ] = "copy-bits",
  38. [ QXL_DRAW_BLEND ] = "blend",
  39. [ QXL_DRAW_BLACKNESS ] = "blackness",
  40. [ QXL_DRAW_WHITENESS ] = "whitemess",
  41. [ QXL_DRAW_INVERS ] = "invers",
  42. [ QXL_DRAW_ROP3 ] = "rop3",
  43. [ QXL_DRAW_STROKE ] = "stroke",
  44. [ QXL_DRAW_TEXT ] = "text",
  45. [ QXL_DRAW_TRANSPARENT ] = "transparent",
  46. [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
  47. };
  48. static const char *const qxl_draw_effect[] = {
  49. [ QXL_EFFECT_BLEND ] = "blend",
  50. [ QXL_EFFECT_OPAQUE ] = "opaque",
  51. [ QXL_EFFECT_REVERT_ON_DUP ] = "revert-on-dup",
  52. [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
  53. [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
  54. [ QXL_EFFECT_NOP_ON_DUP ] = "nop-on-dup",
  55. [ QXL_EFFECT_NOP ] = "nop",
  56. [ QXL_EFFECT_OPAQUE_BRUSH ] = "opaque-brush",
  57. };
  58. static const char *const qxl_surface_cmd[] = {
  59. [ QXL_SURFACE_CMD_CREATE ] = "create",
  60. [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
  61. };
  62. static const char *const spice_surface_fmt[] = {
  63. [ SPICE_SURFACE_FMT_INVALID ] = "invalid",
  64. [ SPICE_SURFACE_FMT_1_A ] = "alpha/1",
  65. [ SPICE_SURFACE_FMT_8_A ] = "alpha/8",
  66. [ SPICE_SURFACE_FMT_16_555 ] = "555/16",
  67. [ SPICE_SURFACE_FMT_16_565 ] = "565/16",
  68. [ SPICE_SURFACE_FMT_32_xRGB ] = "xRGB/32",
  69. [ SPICE_SURFACE_FMT_32_ARGB ] = "ARGB/32",
  70. };
  71. static const char *const qxl_cursor_cmd[] = {
  72. [ QXL_CURSOR_SET ] = "set",
  73. [ QXL_CURSOR_MOVE ] = "move",
  74. [ QXL_CURSOR_HIDE ] = "hide",
  75. [ QXL_CURSOR_TRAIL ] = "trail",
  76. };
  77. static const char *const spice_cursor_type[] = {
  78. [ SPICE_CURSOR_TYPE_ALPHA ] = "alpha",
  79. [ SPICE_CURSOR_TYPE_MONO ] = "mono",
  80. [ SPICE_CURSOR_TYPE_COLOR4 ] = "color4",
  81. [ SPICE_CURSOR_TYPE_COLOR8 ] = "color8",
  82. [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
  83. [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
  84. [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
  85. };
  86. static const char *qxl_v2n(const char *const n[], size_t l, int v)
  87. {
  88. if (v >= l || !n[v]) {
  89. return "???";
  90. }
  91. return n[v];
  92. }
  93. #define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
  94. static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
  95. {
  96. QXLImage *image;
  97. QXLImageDescriptor *desc;
  98. image = qxl_phys2virt(qxl, addr, group_id);
  99. if (!image) {
  100. return 1;
  101. }
  102. desc = &image->descriptor;
  103. fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
  104. desc->id, desc->type, desc->flags, desc->width, desc->height);
  105. switch (desc->type) {
  106. case SPICE_IMAGE_TYPE_BITMAP:
  107. fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
  108. " palette %" PRIx64 " data %" PRIx64,
  109. image->bitmap.format, image->bitmap.flags,
  110. image->bitmap.x, image->bitmap.y,
  111. image->bitmap.stride,
  112. image->bitmap.palette, image->bitmap.data);
  113. break;
  114. }
  115. fprintf(stderr, ")");
  116. return 0;
  117. }
  118. static void qxl_log_rect(QXLRect *rect)
  119. {
  120. fprintf(stderr, " %dx%d+%d+%d",
  121. rect->right - rect->left,
  122. rect->bottom - rect->top,
  123. rect->left, rect->top);
  124. }
  125. static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy,
  126. int group_id)
  127. {
  128. int ret;
  129. fprintf(stderr, " src %" PRIx64,
  130. copy->src_bitmap);
  131. ret = qxl_log_image(qxl, copy->src_bitmap, group_id);
  132. if (ret != 0) {
  133. return ret;
  134. }
  135. fprintf(stderr, " area");
  136. qxl_log_rect(&copy->src_area);
  137. fprintf(stderr, " rop %d", copy->rop_descriptor);
  138. return 0;
  139. }
  140. static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
  141. {
  142. fprintf(stderr, ": surface_id %d type %s effect %s",
  143. draw->surface_id,
  144. qxl_name(qxl_draw_type, draw->type),
  145. qxl_name(qxl_draw_effect, draw->effect));
  146. switch (draw->type) {
  147. case QXL_DRAW_COPY:
  148. return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
  149. break;
  150. }
  151. return 0;
  152. }
  153. static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
  154. int group_id)
  155. {
  156. fprintf(stderr, ": type %s effect %s",
  157. qxl_name(qxl_draw_type, draw->type),
  158. qxl_name(qxl_draw_effect, draw->effect));
  159. if (draw->bitmap_offset) {
  160. fprintf(stderr, ": bitmap %d",
  161. draw->bitmap_offset);
  162. qxl_log_rect(&draw->bitmap_area);
  163. }
  164. switch (draw->type) {
  165. case QXL_DRAW_COPY:
  166. return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
  167. break;
  168. }
  169. return 0;
  170. }
  171. static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
  172. {
  173. fprintf(stderr, ": %s id %d",
  174. qxl_name(qxl_surface_cmd, cmd->type),
  175. cmd->surface_id);
  176. if (cmd->type == QXL_SURFACE_CMD_CREATE) {
  177. fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
  178. cmd->u.surface_create.width,
  179. cmd->u.surface_create.height,
  180. cmd->u.surface_create.stride,
  181. qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
  182. qxl->guest_surfaces.count, qxl->guest_surfaces.max);
  183. }
  184. if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
  185. fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
  186. }
  187. }
  188. int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
  189. {
  190. QXLCursor *cursor;
  191. fprintf(stderr, ": %s",
  192. qxl_name(qxl_cursor_cmd, cmd->type));
  193. switch (cmd->type) {
  194. case QXL_CURSOR_SET:
  195. fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
  196. cmd->u.set.position.x,
  197. cmd->u.set.position.y,
  198. cmd->u.set.visible ? "yes" : "no",
  199. cmd->u.set.shape);
  200. cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
  201. if (!cursor) {
  202. return 1;
  203. }
  204. fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
  205. " unique 0x%" PRIx64 " data-size %d",
  206. qxl_name(spice_cursor_type, cursor->header.type),
  207. cursor->header.width, cursor->header.height,
  208. cursor->header.hot_spot_x, cursor->header.hot_spot_y,
  209. cursor->header.unique, cursor->data_size);
  210. break;
  211. case QXL_CURSOR_MOVE:
  212. fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
  213. break;
  214. }
  215. return 0;
  216. }
  217. int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
  218. {
  219. bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
  220. void *data;
  221. int ret;
  222. if (!qxl->cmdlog) {
  223. return 0;
  224. }
  225. fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
  226. qxl->id, ring);
  227. fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
  228. qxl_name(qxl_type, ext->cmd.type),
  229. compat ? "(compat)" : "");
  230. data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
  231. if (!data) {
  232. return 1;
  233. }
  234. switch (ext->cmd.type) {
  235. case QXL_CMD_DRAW:
  236. if (!compat) {
  237. ret = qxl_log_cmd_draw(qxl, data, ext->group_id);
  238. } else {
  239. ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
  240. }
  241. if (ret) {
  242. return ret;
  243. }
  244. break;
  245. case QXL_CMD_SURFACE:
  246. qxl_log_cmd_surface(qxl, data);
  247. break;
  248. case QXL_CMD_CURSOR:
  249. qxl_log_cmd_cursor(qxl, data, ext->group_id);
  250. break;
  251. }
  252. fprintf(stderr, "\n");
  253. return 0;
  254. }