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