qxl-logger.c 8.6 KB

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