@samitouri / QOSamiQemu / commits / c6e94d24fb

ui/console: return completion status from gfx_update callback

Replace the two-field design (gfx_update void callback + gfx_update_async flag) with a single bool return value from gfx_update. Returning true means the update completed synchronously and graphic_hw_update_done() should be called by the console layer. Returning false means the update is deferred and the device will call graphic_hw_update_done() itself later (as done by QXL/SPICE and Apple GFX). This simplifies the interface and makes the async contract explicit at each call site rather than relying on a separate struct field. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Marc-André Lureau committed Mar 5, 2026 at 13:58 UTC c6e94d24fb81b482dcce9df8311062e4847d6cc6
32 files changed +132 -89
hw/arm/musicpal.c
+2 -1
@@ -152,7 +152,7 @@ static inline void set_lcd_pixel32(musicpal_lcd_state *s,
152 }
153 }
154
155 -static void lcd_refresh(void *opaque)
155 +static bool lcd_refresh(void *opaque)
156 {
157 musicpal_lcd_state *s = opaque;
158 int x, y, col;
@@ -171,6 +171,7 @@ static void lcd_refresh(void *opaque)
171 }
172
173 dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
174 + return true;
175 }
176
177 static void lcd_invalidate(void *opaque)
hw/display/apple-gfx.m
+5 -5
@@ -330,25 +330,25 @@ static void apple_gfx_render_frame_completed_bh(void *opaque)
330 }
331 }
332
333 -static void apple_gfx_fb_update_display(void *opaque)
333 +static bool apple_gfx_fb_update_display(void *opaque)
334 {
335 AppleGFXState *s = opaque;
336 + bool done = true;
337
338 assert(bql_locked());
339 if (s->new_frame_ready) {
340 dpy_gfx_update_full(s->con);
341 s->new_frame_ready = false;
341 - graphic_hw_update_done(s->con);
342 } else if (s->pending_frames > 0) {
343 s->gfx_update_requested = true;
344 - } else {
345 - graphic_hw_update_done(s->con);
344 + done = false;
345 }
346 +
347 + return done;
348 }
349
350 static const GraphicHwOps apple_gfx_fb_ops = {
351 .gfx_update = apple_gfx_fb_update_display,
351 - .gfx_update_async = true,
352 };
353
354 /* ------ Mouse cursor and display mode setting ------ */
hw/display/artist.c
+3 -1
@@ -1311,7 +1311,7 @@ static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
1311 }
1312 }
1313
1314 -static void artist_update_display(void *opaque)
1314 +static bool artist_update_display(void *opaque)
1315 {
1316 ARTISTState *s = opaque;
1317 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -1326,6 +1326,8 @@ static void artist_update_display(void *opaque)
1326 if (first >= 0) {
1327 dpy_gfx_update(s->con, 0, first, s->width, last - first + 1);
1328 }
1329 +
1330 + return true;
1331 }
1332
1333 static void artist_invalidate(void *opaque)
hw/display/bcm2835_fb.c
+4 -3
@@ -150,7 +150,7 @@ static bool fb_use_offsets(BCM2835FBConfig *config)
150 config->yres_virtual > config->yres;
151 }
152
153 -static void fb_update_display(void *opaque)
153 +static bool fb_update_display(void *opaque)
154 {
155 BCM2835FBState *s = opaque;
156 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -161,7 +161,7 @@ static void fb_update_display(void *opaque)
161 uint32_t xoff = 0, yoff = 0;
162
163 if (s->lock || !s->config.xres) {
164 - return;
164 + return true;
165 }
166
167 src_width = bcm2835_fb_get_pitch(&s->config);
@@ -174,7 +174,7 @@ static void fb_update_display(void *opaque)
174
175 switch (surface_bits_per_pixel(surface)) {
176 case 0:
177 - return;
177 + return true;
178 case 8:
179 break;
180 case 15:
@@ -212,6 +212,7 @@ static void fb_update_display(void *opaque)
212 }
213
214 s->invalidate = false;
215 + return true;
216 }
217
218 void bcm2835_fb_validate_config(BCM2835FBConfig *config)
hw/display/bochs-display.c
+4 -2
@@ -198,7 +198,7 @@ static int bochs_display_get_mode(BochsDisplayState *s,
198 return 0;
199 }
200
201 -static void bochs_display_update(void *opaque)
201 +static bool bochs_display_update(void *opaque)
202 {
203 BochsDisplayState *s = opaque;
204 DirtyBitmapSnapshot *snap = NULL;
@@ -212,7 +212,7 @@ static void bochs_display_update(void *opaque)
212 ret = bochs_display_get_mode(s, &mode);
213 if (ret < 0) {
214 /* no (valid) video mode */
215 - return;
215 + return true;
216 }
217
218 if (memcmp(&s->mode, &mode, sizeof(mode)) != 0) {
@@ -255,6 +255,8 @@ static void bochs_display_update(void *opaque)
255
256 g_free(snap);
257 }
258 +
259 + return true;
260 }
261
262 static const GraphicHwOps bochs_display_gfx_ops = {
hw/display/cg3.c
+3 -2
@@ -85,7 +85,7 @@ struct CG3State {
85 uint8_t dac_index, dac_state;
86 };
87
88 -static void cg3_update_display(void *opaque)
88 +static bool cg3_update_display(void *opaque)
89 {
90 CG3State *s = opaque;
91 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -98,7 +98,7 @@ static void cg3_update_display(void *opaque)
98 DirtyBitmapSnapshot *snap = NULL;
99
100 if (surface_bits_per_pixel(surface) != 32) {
101 - return;
101 + return true;
102 }
103 width = s->width;
104 height = s->height;
@@ -154,6 +154,7 @@ static void cg3_update_display(void *opaque)
154 qemu_irq_raise(s->irq);
155 }
156 g_free(snap);
157 + return true;
158 }
159
160 static void cg3_invalidate_display(void *opaque)
hw/display/dm163.c
+3 -1
@@ -285,7 +285,7 @@ static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
285 return dest;
286 }
287
288 -static void dm163_update_display(void *opaque)
288 +static bool dm163_update_display(void *opaque)
289 {
290 DM163State *s = (DM163State *)opaque;
291 DisplaySurface *surface = qemu_console_surface(s->console);
@@ -300,6 +300,8 @@ static void dm163_update_display(void *opaque)
300 }
301 dest = update_display_of_row(s, dest, row);
302 }
303 +
304 + return true;
305 }
306
307 static const GraphicHwOps dm163_ops = {
hw/display/exynos4210_fimd.c
+4 -2
@@ -1270,7 +1270,7 @@ static void exynos4210_update_resolution(Exynos4210fimdState *s)
1270 }
1271 }
1272
1273 -static void exynos4210_fimd_update(void *opaque)
1273 +static bool exynos4210_fimd_update(void *opaque)
1274 {
1275 Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
1276 DisplaySurface *surface;
@@ -1287,7 +1287,7 @@ static void exynos4210_fimd_update(void *opaque)
1287
1288 if (!s || !s->console || !s->enabled ||
1289 surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) {
1290 - return;
1290 + return true;
1291 }
1292
1293 global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
@@ -1348,6 +1348,8 @@ static void exynos4210_fimd_update(void *opaque)
1348 exynos4210_fimd_enable(s, false);
1349 }
1350 exynos4210_fimd_update_irq(s);
1351 +
1352 + return true;
1353 }
1354
1355 static void exynos4210_fimd_reset(DeviceState *d)
hw/display/g364fb.c
+6 -3
@@ -238,15 +238,16 @@ static void g364fb_draw_blank(G364State *s)
238 s->blanked = 1;
239 }
240
241 -static void g364fb_update_display(void *opaque)
241 +static bool g364fb_update_display(void *opaque)
242 {
243 G364State *s = opaque;
244 DisplaySurface *surface = qemu_console_surface(s->con);
245
246 qemu_flush_coalesced_mmio_buffer();
247
248 - if (s->width == 0 || s->height == 0)
249 - return;
248 + if (s->width == 0 || s->height == 0) {
249 + return true;
250 + }
251
252 if (s->width != surface_width(surface) ||
253 s->height != surface_height(surface)) {
@@ -262,6 +263,8 @@ static void g364fb_update_display(void *opaque)
263 }
264
265 qemu_irq_raise(s->irq);
266 +
267 + return true;
268 }
269
270 static inline void g364fb_invalidate_display(void *opaque)
hw/display/imx6ul_lcdif.c
+4 -3
@@ -152,7 +152,7 @@ static void imx6ul_lcdif_draw_line_xrgb8888(void *opaque, uint8_t *dst,
152 }
153 }
154
155 -static void imx6ul_lcdif_update_display(void *opaque)
155 +static bool imx6ul_lcdif_update_display(void *opaque)
156 {
157 IMX6ULLCDIFState *s = opaque;
158 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -167,7 +167,7 @@ static void imx6ul_lcdif_update_display(void *opaque)
167 int src_width;
168
169 if (!imx6ul_lcdif_is_running(s) || width == 0 || height == 0) {
170 - return;
170 + return true;
171 }
172
173 switch (FIELD_EX32(ctrl, CTRL, WORD_LENGTH)) {
@@ -180,7 +180,7 @@ static void imx6ul_lcdif_update_display(void *opaque)
180 fn = imx6ul_lcdif_draw_line_xrgb8888;
181 break;
182 default:
183 - return;
183 + return true;
184 }
185
186 if (surface_width(surface) != width || surface_height(surface) != height) {
@@ -207,6 +207,7 @@ static void imx6ul_lcdif_update_display(void *opaque)
207 }
208
209 s->invalidate = false;
210 + return true;
211 }
212
213 static void imx6ul_lcdif_invalidate_display(void *opaque)
hw/display/jazz_led.c
+4 -2
@@ -144,7 +144,7 @@ static void draw_vertical_line(DisplaySurface *ds,
144 }
145 }
146
147 -static void jazz_led_update_display(void *opaque)
147 +static bool jazz_led_update_display(void *opaque)
148 {
149 LedState *s = opaque;
150 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -186,7 +186,7 @@ static void jazz_led_update_display(void *opaque)
186 color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
187 break;
188 default:
189 - return;
189 + return true;
190 }
191
192 /* display segments */
@@ -218,6 +218,8 @@ static void jazz_led_update_display(void *opaque)
218
219 s->state = REDRAW_NONE;
220 dpy_gfx_update_full(s->con);
221 +
222 + return true;
223 }
224
225 static void jazz_led_invalidate_display(void *opaque)
hw/display/macfb.c
+4 -2
@@ -454,7 +454,7 @@ static gchar *macfb_mode_list(void)
454 }
455
456
457 -static void macfb_update_display(void *opaque)
457 +static bool macfb_update_display(void *opaque)
458 {
459 MacfbState *s = opaque;
460 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -462,7 +462,7 @@ static void macfb_update_display(void *opaque)
462 qemu_flush_coalesced_mmio_buffer();
463
464 if (s->width == 0 || s->height == 0) {
465 - return;
465 + return true;
466 }
467
468 if (s->width != surface_width(surface) ||
@@ -471,6 +471,8 @@ static void macfb_update_display(void *opaque)
471 }
472
473 macfb_draw_graphic(s);
474 +
475 + return true;
476 }
477
478 static void macfb_update_irq(MacfbState *s)
hw/display/next-fb.c
+3 -1
@@ -67,7 +67,7 @@ static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s,
67 }
68 }
69
70 -static void nextfb_update(void *opaque)
70 +static bool nextfb_update(void *opaque)
71 {
72 NeXTFbState *s = NEXTFB(opaque);
73 int dest_width = 4;
@@ -90,6 +90,8 @@ static void nextfb_update(void *opaque)
90 s, &first, &last);
91
92 dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
93 +
94 + return true;
95 }
96
97 static void nextfb_invalidate(void *opaque)
hw/display/omap_lcdc.c
+8 -6
@@ -197,7 +197,7 @@ static void draw_line16_32(void *opaque, uint8_t *d, const uint8_t *s,
197 } while (-- width != 0);
198 }
199
200 -static void omap_update_display(void *opaque)
200 +static bool omap_update_display(void *opaque)
201 {
202 struct omap_lcd_panel_s *omap_lcd = opaque;
203 DisplaySurface *surface;
@@ -207,12 +207,12 @@ static void omap_update_display(void *opaque)
207 hwaddr frame_base;
208
209 if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable) {
210 - return;
210 + return true;
211 }
212
213 surface = qemu_console_surface(omap_lcd->con);
214 if (!surface_bits_per_pixel(surface)) {
215 - return;
215 + return true;
216 }
217
218 frame_offset = 0;
@@ -256,7 +256,7 @@ static void omap_update_display(void *opaque)
256
257 default:
258 /* Unsupported at the moment. */
259 - return;
259 + return true;
260 }
261
262 /* Resolution */
@@ -278,7 +278,7 @@ static void omap_update_display(void *opaque)
278 omap_lcd->sync_error = 1;
279 omap_lcd_interrupts(omap_lcd);
280 omap_lcd->enable = 0;
281 - return;
281 + return true;
282 }
283
284 /* Content */
@@ -291,7 +291,7 @@ static void omap_update_display(void *opaque)
291 omap_lcd->dma->current_frame ^= 1;
292
293 if (!surface_bits_per_pixel(surface)) {
294 - return;
294 + return true;
295 }
296
297 first = 0;
@@ -323,6 +323,8 @@ static void omap_update_display(void *opaque)
323 dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
324 }
325 omap_lcd->invalidate = 0;
326 +
327 + return true;
328 }
329
330 static void omap_invalidate_display(void *opaque) {
hw/display/pl110.c
+3 -2
@@ -210,7 +210,7 @@ static int pl110_enabled(PL110State *s)
210 return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
211 }
212
213 -static void pl110_update_display(void *opaque)
213 +static bool pl110_update_display(void *opaque)
214 {
215 PL110State *s = (PL110State *)opaque;
216 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -221,7 +221,7 @@ static void pl110_update_display(void *opaque)
221 int last;
222
223 if (!pl110_enabled(s)) {
224 - return;
224 + return true;
225 }
226
227 if (s->cr & PL110_CR_BGR)
@@ -306,6 +306,7 @@ static void pl110_update_display(void *opaque)
306 dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
307 }
308 s->invalidate = 0;
309 + return true;
310 }
311
312 static void pl110_invalidate_display(void * opaque)
hw/display/qxl-render.c
+3 -3
@@ -173,7 +173,7 @@ end:
173 * callbacks are called by spice_server thread, deferring to bh called from the
174 * io thread.
175 */
176 -void qxl_render_update(PCIQXLDevice *qxl)
176 +bool qxl_render_update(PCIQXLDevice *qxl)
177 {
178 QXLCookie *cookie;
179
@@ -183,8 +183,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
183 qxl->mode == QXL_MODE_UNDEFINED) {
184 qxl_render_update_area_unlocked(qxl);
185 qemu_mutex_unlock(&qxl->ssd.lock);
186 - graphic_hw_update_done(qxl->ssd.dcl.con);
187 - return;
186 + return true;
187 }
188
189 qxl->guest_primary.commands = 0;
@@ -195,6 +194,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
194 qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
195 qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
196 0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
197 + return false;
198 }
199
200 void qxl_render_update_area_bh(void *opaque)
hw/display/qxl.c
+3 -4
@@ -122,7 +122,7 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
122 static void qxl_reset_surfaces(PCIQXLDevice *d);
123 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
124
125 -static void qxl_hw_update(void *opaque);
125 +static bool qxl_hw_update(void *opaque);
126
127 void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
128 {
@@ -1144,7 +1144,6 @@ static const QXLInterface qxl_interface = {
1144
1145 static const GraphicHwOps qxl_ops = {
1146 .gfx_update = qxl_hw_update,
1147 - .gfx_update_async = true,
1147 };
1148
1149 static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -1928,11 +1927,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
1927
1928 /* graphics console */
1929
1931 -static void qxl_hw_update(void *opaque)
1930 +static bool qxl_hw_update(void *opaque)
1931 {
1932 PCIQXLDevice *qxl = opaque;
1933
1935 - qxl_render_update(qxl);
1934 + return qxl_render_update(qxl);
1935 }
1936
1937 static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
hw/display/qxl.h
+1 -1
@@ -187,7 +187,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
187
188 /* qxl-render.c */
189 void qxl_render_resize(PCIQXLDevice *qxl);
190 -void qxl_render_update(PCIQXLDevice *qxl);
190 +bool qxl_render_update(PCIQXLDevice *qxl);
191 int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
192 void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
193 void qxl_render_update_area_bh(void *opaque);
hw/display/ramfb-standalone.c
+3 -1
@@ -20,7 +20,7 @@ struct RAMFBStandaloneState {
20 bool use_legacy_x86_rom;
21 };
22
23 -static void display_update_wrapper(void *dev)
23 +static bool display_update_wrapper(void *dev)
24 {
25 RAMFBStandaloneState *ramfb = RAMFB(dev);
26
@@ -29,6 +29,8 @@ static void display_update_wrapper(void *dev)
29 } else {
30 ramfb_display_update(ramfb->con, ramfb->state);
31 }
32 +
33 + return true;
34 }
35
36 static const GraphicHwOps wrapper_ops = {
hw/display/sm501.c
+5 -3
@@ -1716,7 +1716,7 @@ static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width,
1716 }
1717 }
1718
1719 -static void sm501_update_display(void *opaque)
1719 +static bool sm501_update_display(void *opaque)
1720 {
1721 SM501State *s = opaque;
1722 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -1740,7 +1740,7 @@ static void sm501_update_display(void *opaque)
1740
1741 if (!((crt ? s->dc_crt_control : s->dc_panel_control)
1742 & SM501_DC_CRT_CONTROL_ENABLE)) {
1743 - return;
1743 + return true;
1744 }
1745
1746 palette = (uint32_t *)(crt ? &s->dc_palette[SM501_DC_CRT_PALETTE -
@@ -1761,7 +1761,7 @@ static void sm501_update_display(void *opaque)
1761 default:
1762 qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display"
1763 "invalid control register value.\n");
1764 - return;
1764 + return true;
1765 }
1766
1767 /* set up to draw hardware cursor */
@@ -1833,6 +1833,8 @@ static void sm501_update_display(void *opaque)
1833 if (y_start >= 0) {
1834 dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
1835 }
1836 +
1837 + return true;
1838 }
1839
1840 static const GraphicHwOps sm501_ops = {
hw/display/ssd0303.c
+6 -4
@@ -203,7 +203,7 @@ static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
203 return 0;
204 }
205
206 -static void ssd0303_update_display(void *opaque)
206 +static bool ssd0303_update_display(void *opaque)
207 {
208 ssd0303_state *s = (ssd0303_state *)opaque;
209 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -218,11 +218,11 @@ static void ssd0303_update_display(void *opaque)
218 uint8_t mask;
219
220 if (!s->redraw)
221 - return;
221 + return true;
222
223 switch (surface_bits_per_pixel(surface)) {
224 case 0:
225 - return;
225 + return true;
226 case 15:
227 dest_width = 2;
228 break;
@@ -237,7 +237,7 @@ static void ssd0303_update_display(void *opaque)
237 break;
238 default:
239 BADF("Bad color depth\n");
240 - return;
240 + return true;
241 }
242 dest_width *= MAGNIFY;
243 memset(colortab, 0xff, dest_width);
@@ -269,6 +269,8 @@ static void ssd0303_update_display(void *opaque)
269 }
270 s->redraw = 0;
271 dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
272 +
273 + return true;
274 }
275
276 static void ssd0303_invalidate_display(void * opaque)
hw/display/ssd0323.c
+6 -5
@@ -181,7 +181,7 @@ static uint32_t ssd0323_transfer(SSIPeripheral *dev, uint32_t data)
181 return 0;
182 }
183
184 -static void ssd0323_update_display(void *opaque)
184 +static bool ssd0323_update_display(void *opaque)
185 {
186 ssd0323_state *s = (ssd0323_state *)opaque;
187 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -197,11 +197,11 @@ static void ssd0323_update_display(void *opaque)
197 int dest_width;
198
199 if (!s->redraw)
200 - return;
200 + return true;
201
202 switch (surface_bits_per_pixel(surface)) {
203 case 0:
204 - return;
204 + return true;
205 case 15:
206 dest_width = 2;
207 break;
@@ -216,7 +216,7 @@ static void ssd0323_update_display(void *opaque)
216 break;
217 default:
218 BADF("Bad color depth\n");
219 - return;
219 + return true;
220 }
221 p = colortab;
222 for (i = 0; i < 16; i++) {
@@ -240,7 +240,7 @@ static void ssd0323_update_display(void *opaque)
240 break;
241 default:
242 BADF("Bad color depth\n");
243 - return;
243 + return true;
244 }
245 p += dest_width;
246 }
@@ -271,6 +271,7 @@ static void ssd0323_update_display(void *opaque)
271 }
272 s->redraw = 0;
273 dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
274 + return true;
275 }
276
277 static void ssd0323_invalidate_display(void * opaque)
hw/display/tcx.c
+4 -2
@@ -209,7 +209,7 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
209 /* Fixed line length 1024 allows us to do nice tricks not possible on
210 VGA... */
211
212 -static void tcx_update_display(void *opaque)
212 +static bool tcx_update_display(void *opaque)
213 {
214 TCXState *ts = opaque;
215 DisplaySurface *surface = qemu_console_surface(ts->con);
@@ -257,9 +257,10 @@ static void tcx_update_display(void *opaque)
257 ts->width, y - y_start);
258 }
259 g_free(snap);
260 + return true;
261 }
262
262 -static void tcx24_update_display(void *opaque)
263 +static bool tcx24_update_display(void *opaque)
264 {
265 TCXState *ts = opaque;
266 DisplaySurface *surface = qemu_console_surface(ts->con);
@@ -312,6 +313,7 @@ static void tcx24_update_display(void *opaque)
313 ts->width, y - y_start);
314 }
315 g_free(snap);
316 + return true;
317 }
318
319 static void tcx_invalidate_display(void *opaque)
hw/display/vga.c
+3 -1
@@ -1783,7 +1783,7 @@ static void vga_draw_blank(VGACommonState *s, int full_update)
1783 #define GMODE_GRAPH 1
1784 #define GMODE_BLANK 2
1785
1786 -static void vga_update_display(void *opaque)
1786 +static bool vga_update_display(void *opaque)
1787 {
1788 VGACommonState *s = opaque;
1789 DisplaySurface *surface = qemu_console_surface(s->con);
@@ -1818,6 +1818,8 @@ static void vga_update_display(void *opaque)
1818 break;
1819 }
1820 }
1821 +
1822 + return true;
1823 }
1824
1825 /* force a full display refresh */
hw/display/virtio-gpu-base.c
+2 -1
@@ -83,8 +83,9 @@ static void virtio_gpu_invalidate_display(void *opaque)
83 {
84 }
85
86 -static void virtio_gpu_update_display(void *opaque)
86 +static bool virtio_gpu_update_display(void *opaque)
87 {
88 + return true;
89 }
90
91 static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
hw/display/virtio-vga.c
+3 -3
@@ -19,15 +19,15 @@ static void virtio_vga_base_invalidate_display(void *opaque)
19 }
20 }
21
22 -static void virtio_vga_base_update_display(void *opaque)
22 +static bool virtio_vga_base_update_display(void *opaque)
23 {
24 VirtIOVGABase *vvga = opaque;
25 VirtIOGPUBase *g = vvga->vgpu;
26
27 if (g->enable) {
28 - g->hw_ops->gfx_update(g);
28 + return g->hw_ops->gfx_update(g);
29 } else {
30 - vvga->vga.hw_ops->gfx_update(&vvga->vga);
30 + return vvga->vga.hw_ops->gfx_update(&vvga->vga);
31 }
32 }
33
hw/display/vmware_vga.c
+4 -3
@@ -1135,14 +1135,13 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s)
1135 }
1136 }
1137
1138 -static void vmsvga_update_display(void *opaque)
1138 +static bool vmsvga_update_display(void *opaque)
1139 {
1140 struct vmsvga_state_s *s = opaque;
1141
1142 if (!s->enable || !s->config) {
1143 /* in standard vga mode */
1144 - s->vga.hw_ops->gfx_update(&s->vga);
1145 - return;
1144 + return s->vga.hw_ops->gfx_update(&s->vga);
1145 }
1146
1147 vmsvga_check_size(s);
@@ -1154,6 +1153,8 @@ static void vmsvga_update_display(void *opaque)
1153 s->invalidated = 0;
1154 dpy_gfx_update_full(s->vga.con);
1155 }
1156 +
1157 + return true;
1158 }
1159
1160 static void vmsvga_reset(DeviceState *dev)
hw/display/xenfb.c
+4 -2
@@ -709,14 +709,14 @@ static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
709 * Our screen might be inactive. When asked for
710 * an update we know it is active.
711 */
712 -static void xenfb_update(void *opaque)
712 +static bool xenfb_update(void *opaque)
713 {
714 struct XenFB *xenfb = opaque;
715 DisplaySurface *surface;
716 int i;
717
718 if (xenfb->c.xendev.be_state != XenbusStateConnected)
719 - return;
719 + return true;
720
721 if (!xenfb->feature_update) {
722 /* we don't get update notifications, thus use the
@@ -770,6 +770,8 @@ static void xenfb_update(void *opaque)
770 }
771 xenfb->up_count = 0;
772 xenfb->up_fullscreen = 0;
773 +
774 + return true;
775 }
776
777 static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
hw/display/xlnx_dp.c
+6 -4
@@ -1252,12 +1252,12 @@ static inline void xlnx_dp_blend_surface(XlnxDPState *s)
1252 surface_height(s->g_plane.surface));
1253 }
1254
1255 -static void xlnx_dp_update_display(void *opaque)
1255 +static bool xlnx_dp_update_display(void *opaque)
1256 {
1257 XlnxDPState *s = XLNX_DP(opaque);
1258
1259 if ((s->core_registers[DP_TRANSMITTER_ENABLE] & 0x01) == 0) {
1260 - return;
1260 + return true;
1261 }
1262
1263 xlnx_dpdma_trigger_vsync_irq(s->dpdma);
@@ -1272,14 +1272,14 @@ static void xlnx_dp_update_display(void *opaque)
1272 */
1273 s->core_registers[DP_INT_STATUS] |= (1 << 21);
1274 xlnx_dp_update_irq(s);
1275 - return;
1275 + return true;
1276 }
1277
1278 if (xlnx_dp_global_alpha_enabled(s)) {
1279 if (!xlnx_dpdma_start_operation(s->dpdma, 0, false)) {
1280 s->core_registers[DP_INT_STATUS] |= (1 << 21);
1281 xlnx_dp_update_irq(s);
1282 - return;
1282 + return true;
1283 }
1284 xlnx_dp_blend_surface(s);
1285 }
@@ -1288,6 +1288,8 @@ static void xlnx_dp_update_display(void *opaque)
1288 * XXX: We might want to update only what changed.
1289 */
1290 dpy_gfx_update_full(s->console);
1291 +
1292 + return true;
1293 }
1294
1295 static const GraphicHwOps xlnx_dp_gfx_ops = {
hw/vfio/display.c
+10 -7
@@ -285,7 +285,7 @@ static void vfio_display_free_dmabufs(VFIOPCIDevice *vdev)
285 }
286 }
287
288 -static void vfio_display_dmabuf_update(void *opaque)
288 +static bool vfio_display_dmabuf_update(void *opaque)
289 {
290 VFIOPCIDevice *vdev = opaque;
291 VFIODisplay *dpy = vdev->dpy;
@@ -298,7 +298,7 @@ static void vfio_display_dmabuf_update(void *opaque)
298 if (dpy->ramfb) {
299 ramfb_display_update(dpy->con, dpy->ramfb);
300 }
301 - return;
301 + return true;
302 }
303
304 width = qemu_dmabuf_get_width(primary->buf);
@@ -340,6 +340,8 @@ static void vfio_display_dmabuf_update(void *opaque)
340 if (free_bufs) {
341 vfio_display_free_dmabufs(vdev);
342 }
343 +
344 + return true;
345 }
346
347 static int vfio_display_get_flags(void *opaque)
@@ -399,7 +401,7 @@ void vfio_display_reset(VFIOPCIDevice *vdev)
401 dpy_gfx_update_full(vdev->dpy->con);
402 }
403
402 -static void vfio_display_region_update(void *opaque)
404 +static bool vfio_display_region_update(void *opaque)
405 {
406 VFIOPCIDevice *vdev = opaque;
407 VFIODisplay *dpy = vdev->dpy;
@@ -414,18 +416,18 @@ static void vfio_display_region_update(void *opaque)
416 if (ret < 0) {
417 error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
418 strerror(errno));
417 - return;
419 + return true;
420 }
421 if (!plane.drm_format || !plane.size) {
422 if (dpy->ramfb) {
423 ramfb_display_update(dpy->con, dpy->ramfb);
424 dpy->region.surface = NULL;
425 }
424 - return;
426 + return true;
427 }
428 format = qemu_drm_format_to_pixman(plane.drm_format);
429 if (!format) {
428 - return;
430 + return true;
431 }
432
433 if (dpy->region.buffer.size &&
@@ -476,11 +478,12 @@ static void vfio_display_region_update(void *opaque)
478 dpy_gfx_update(dpy->con, 0, 0,
479 surface_width(dpy->region.surface),
480 surface_height(dpy->region.surface));
479 - return;
481 + return true;
482
483 err:
484 vfio_region_exit(&dpy->region.buffer);
485 vfio_region_finalize(&dpy->region.buffer);
486 + return true;
487 }
488
489 static const GraphicHwOps vfio_display_region_ops = {
include/ui/console.h
+8 -3
@@ -368,9 +368,14 @@ enum {
368 typedef struct GraphicHwOps {
369 int (*get_flags)(void *opaque); /* optional, default 0 */
370 void (*invalidate)(void *opaque);
371 - void (*gfx_update)(void *opaque);
372 - bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
373 - void (*text_update)(void *opaque, console_ch_t *text);
371 + /*
372 + * Returns true if the update is handled synchronously, false if deferred
373 + * and graphic_hw_update_done() will be called when ready (to resume waiting
374 + * tasks/coroutines).
375 + * Optional.
376 + */
377 + bool (*gfx_update)(void *opaque);
378 + void (*text_update)(void *opaque, uint32_t *text);
379 void (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
380 void (*gl_block)(void *opaque, bool block);
381 } GraphicHwOps;
ui/console.c
+1 -6
@@ -136,15 +136,10 @@ void graphic_hw_update_done(QemuConsole *con)
136
137 void graphic_hw_update(QemuConsole *con)
138 {
139 - bool async = false;
139 if (!con) {
140 return;
141 }
143 - if (con->hw_ops->gfx_update) {
144 - con->hw_ops->gfx_update(con->hw);
145 - async = con->hw_ops->gfx_update_async;
146 - }
147 - if (!async) {
142 + if (!con->hw_ops->gfx_update || con->hw_ops->gfx_update(con->hw)) {
143 graphic_hw_update_done(con);
144 }
145 }