vmwgfx_saa.c revision 591e32d7
1/*
2 * Copyright 2011 VMWare, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Author: Thomas Hellstrom <thellstrom@vmware.com>
26 */
27
28#include <xorg-server.h>
29#include <xorgVersion.h>
30#include <mi.h>
31#include <fb.h>
32#include <xf86drmMode.h>
33#include <xa_context.h>
34#include "vmwgfx_saa.h"
35#include "vmwgfx_drmi.h"
36#include "vmwgfx_saa_priv.h"
37
38/*
39 * Damage to be added as soon as we attach storage to the pixmap.
40 */
41static Bool
42vmwgfx_pixmap_add_damage(PixmapPtr pixmap)
43{
44    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
45    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
46    DrawablePtr draw = &pixmap->drawable;
47    BoxRec box;
48
49    if (spix->damage)
50	return TRUE;
51
52    if (!saa_add_damage(pixmap))
53	return FALSE;
54
55    box.x1 = 0;
56    box.x2 = draw->width;
57    box.y1 = 0;
58    box.y2 = draw->height;
59
60    if (vpix->hw) {
61	REGION_RESET(draw->pScreen, &spix->dirty_hw, &box);
62	REGION_EMPTY(draw->pScreen, &spix->dirty_shadow);
63    } else {
64	REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box);
65	REGION_EMPTY(draw->pScreen, &spix->dirty_hw);
66    }
67
68    return TRUE;
69}
70
71static void
72vmwgfx_pixmap_remove_damage(PixmapPtr pixmap)
73{
74    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
75    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
76
77    if (!spix->damage || vpix->hw || vpix->gmr || vpix->malloc)
78	return;
79
80#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
81    DamageUnregister(spix->damage);
82#else
83    DamageUnregister(&pixmap->drawable, spix->damage);
84#endif
85
86    DamageDestroy(spix->damage);
87    spix->damage = NULL;
88}
89
90static void
91vmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix)
92{
93    if (vpix->dirty_present)
94	REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present);
95    if (vpix->present_damage)
96	REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage);
97    if (vpix->pending_update)
98	REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update);
99    if (vpix->pending_present)
100	REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present);
101    vpix->dirty_present = NULL;
102    vpix->present_damage = NULL;
103    vpix->pending_update = NULL;
104    vpix->pending_present = NULL;
105}
106
107static Bool
108vmwgfx_pixmap_add_present(PixmapPtr pixmap, Bool present_opt)
109{
110    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
111    ScreenPtr pScreen = pixmap->drawable.pScreen;
112    (void) pScreen;
113
114    if (present_opt) {
115	vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0);
116	if (!vpix->dirty_present)
117	    return FALSE;
118	vpix->present_damage = REGION_CREATE(pScreen, NULL, 0);
119	if (!vpix->present_damage)
120	    goto out_no_present_damage;
121    }
122    vpix->pending_update = REGION_CREATE(pScreen, NULL, 0);
123    if (!vpix->pending_update)
124	goto out_no_pending_update;
125    vpix->pending_present = REGION_CREATE(pScreen, NULL, 0);
126    if (!vpix->pending_present)
127	goto out_no_pending_present;
128
129    return TRUE;
130  out_no_pending_present:
131    REGION_DESTROY(pScreen, vpix->pending_update);
132  out_no_pending_update:
133    if (vpix->present_damage)
134	REGION_DESTROY(pScreen, vpix->present_damage);
135  out_no_present_damage:
136    if (vpix->dirty_present)
137	REGION_DESTROY(pScreen, vpix->dirty_present);
138    return FALSE;
139}
140
141static void
142vmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix)
143{
144    if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) {
145	free(vpix->malloc);
146	vpix->malloc = NULL;
147    }
148    if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) {
149	xa_surface_destroy(vpix->hw);
150	vpix->hw = NULL;
151    }
152    if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) {
153	vmwgfx_dmabuf_destroy(vpix->gmr);
154	vpix->gmr = NULL;
155    }
156}
157
158static Bool
159vmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
160{
161    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
162    size_t size;
163    struct vmwgfx_dmabuf *gmr;
164    void *addr;
165
166    if (vpix->gmr)
167	return TRUE;
168
169    size = pixmap->devKind * pixmap->drawable.height;
170    gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
171    if (!gmr)
172	return FALSE;
173
174    if (vpix->malloc) {
175
176	addr = vmwgfx_dmabuf_map(gmr);
177	if (!addr)
178	    goto out_no_transfer;
179	memcpy(addr, vpix->malloc, size);
180	vmwgfx_dmabuf_unmap(gmr);
181
182    } else if (!vmwgfx_pixmap_add_damage(pixmap))
183	goto out_no_transfer;
184
185    vpix->backing |= VMWGFX_PIX_GMR;
186    vpix->backing &= ~VMWGFX_PIX_MALLOC;
187    vpix->gmr = gmr;
188
189    vmwgfx_pixmap_free_storage(vpix);
190
191    return TRUE;
192
193  out_no_transfer:
194    vmwgfx_dmabuf_destroy(gmr);
195    return FALSE;
196}
197
198static Bool
199vmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
200{
201    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
202
203    if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR)))
204	return FALSE;
205
206    if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) {
207	vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height);
208	if (!vpix->malloc)
209	    goto out_no_malloc;
210	if (!vmwgfx_pixmap_add_damage(pixmap))
211	    goto out_no_damage;
212    } else if (vpix->backing & VMWGFX_PIX_GMR)
213	return vmwgfx_pixmap_create_gmr(vsaa, pixmap);
214
215    return TRUE;
216
217  out_no_damage:
218    free(vpix->malloc);
219    vpix->malloc = NULL;
220  out_no_malloc:
221    return FALSE;
222}
223
224
225/**
226 *
227 * Makes sure all presented contents covered by @region are read
228 * back and are present in a valid GMR.
229 */
230
231static Bool
232vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa,
233			       PixmapPtr pixmap,
234			       RegionPtr region)
235{
236    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
237    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
238    RegionRec intersection;
239
240    if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) ||
241	!vpix->dirty_present)
242	return TRUE;
243
244    /*
245     * Intersect dirty region with region to be read back, if any.
246     */
247
248    REGION_NULL(vsaa->pScreen, &intersection);
249    REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw);
250    REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection,
251		     vpix->dirty_present);
252
253    if (region)
254	REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region);
255
256    if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection))
257	goto out;
258
259    /*
260     * Make really sure there is a GMR to read back to.
261     */
262
263    if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
264	goto out_err;
265
266    if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id,
267				&intersection) != 0)
268	goto out_err;
269
270    REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw,
271		    &spix->dirty_hw, &intersection);
272  out:
273    REGION_UNINIT(vsaa->pScreen, &intersection);
274    return TRUE;
275
276  out_err:
277    REGION_UNINIT(vsaa->pScreen, &intersection);
278    return FALSE;
279}
280
281static Bool
282vmwgfx_saa_dma(struct vmwgfx_saa *vsaa,
283	       PixmapPtr pixmap,
284	       RegionPtr reg,
285	       Bool to_hw,
286	       int dx,
287	       int dy,
288	       struct xa_surface *srf)
289{
290    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
291
292    if (!srf)
293	srf = vpix->hw;
294
295    if (!srf || (!vpix->gmr && !vpix->malloc))
296	return TRUE;
297
298    if (vpix->gmr && vsaa->can_optimize_dma) {
299	uint32_t handle, dummy;
300
301	if (_xa_surface_handle(srf, &handle, &dummy) != 0)
302	    goto out_err;
303	if (vmwgfx_dma(dx, dy, reg, vpix->gmr, pixmap->devKind, handle,
304		       to_hw) != 0)
305	    goto out_err;
306    } else {
307	uint8_t *data = (uint8_t *) vpix->malloc;
308	int ret;
309
310	if (vpix->gmr) {
311	    data = (uint8_t *) vmwgfx_dmabuf_map(vpix->gmr);
312	    if (!data)
313		goto out_err;
314	}
315
316	if (dx || dy) {
317	    REGION_TRANSLATE(pScreen, reg, dx, dy);
318	    data -= ((dx * pixmap->drawable.bitsPerPixel + 7)/8 +
319		     dy * pixmap->devKind);
320	}
321
322	ret = xa_surface_dma(vsaa->xa_ctx, srf, data, pixmap->devKind,
323			     (int) to_hw,
324			     (struct xa_box *) REGION_RECTS(reg),
325			     REGION_NUM_RECTS(reg));
326	if (to_hw)
327	    xa_context_flush(vsaa->xa_ctx);
328	if (vpix->gmr)
329	    vmwgfx_dmabuf_unmap(vpix->gmr);
330	if (dx || dy)
331	    REGION_TRANSLATE(pScreen, reg, -dx, -dy);
332	if (ret)
333	    goto out_err;
334    }
335    return TRUE;
336  out_err:
337    LogMessage(X_ERROR, "DMA %s surface failed.\n",
338	       to_hw ? "to" : "from");
339    return FALSE;
340}
341
342
343static Bool
344vmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap,
345			RegionPtr readback)
346{
347    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
348    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
349    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
350
351    RegionRec intersection;
352
353    if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback))
354	return FALSE;
355
356    if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw))
357	return TRUE;
358
359    if (!vpix->hw)
360	return TRUE;
361
362    REGION_NULL(vsaa->pScreen, &intersection);
363    REGION_INTERSECT(vsaa->pScreen, &intersection, readback,
364		     &spix->dirty_hw);
365    readback = &intersection;
366
367    if (!vmwgfx_pixmap_create_sw(vsaa, pixmap))
368	goto out_err;
369
370    if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE, 0, 0, NULL))
371	goto out_err;
372    REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback);
373    REGION_UNINIT(vsaa->pScreen, &intersection);
374    return TRUE;
375 out_err:
376    REGION_UNINIT(vsaa->pScreen, &intersection);
377    return FALSE;
378}
379
380
381static Bool
382vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap,
383		    RegionPtr upload)
384{
385    return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE,
386			  0, 0, NULL);
387}
388
389static void
390vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
391{
392  //    LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n",
393  //	       (unsigned long) pixmap, (unsigned) access);
394}
395
396static void *
397vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
398{
399    /*
400     * Errors in this functions will turn up in subsequent map
401     * calls.
402     */
403
404    (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap);
405
406    return NULL;
407}
408
409static void *
410vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
411{
412    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
413
414    if (vpix->malloc)
415	return vpix->malloc;
416    else if (vpix->gmr)
417	return vmwgfx_dmabuf_map(vpix->gmr);
418    else
419	return NULL;
420}
421
422static void
423vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
424{
425    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
426
427    if (vpix->gmr)
428	return vmwgfx_dmabuf_unmap(vpix->gmr);
429
430//    LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n",
431    //       (unsigned long) pixmap, (unsigned) access);
432    ;
433}
434
435static Bool
436vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix,
437		     int w, int h, int depth,
438		     unsigned int usage_hint, int bpp, int *new_pitch)
439{
440    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
441
442    *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
443
444    WSBMINITLISTHEAD(&vpix->sync_x_head);
445    WSBMINITLISTHEAD(&vpix->scanout_list);
446    WSBMINITLISTHEAD(&vpix->pixmap_list);
447
448    return TRUE;
449}
450
451Bool
452vmwgfx_hw_kill(struct vmwgfx_saa *vsaa,
453	       struct saa_pixmap *spix)
454{
455    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
456
457    if (!vpix->hw)
458	return TRUE;
459
460    /*
461     * Read back any dirty regions from hardware.
462     */
463
464    if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
465				 &spix->dirty_hw))
466	return FALSE;
467
468    xa_surface_destroy(vpix->hw);
469    vpix->hw = NULL;
470
471    /*
472     * Remove damage tracking if this is not a scanout pixmap.
473     */
474
475    if (WSBMLISTEMPTY(&vpix->scanout_list))
476	vmwgfx_pixmap_remove_damage(spix->pixmap);
477
478    return TRUE;
479}
480
481void
482vmwgfx_flush_dri2(ScreenPtr pScreen)
483{
484    struct vmwgfx_saa *vsaa =
485	to_vmwgfx_saa(saa_get_driver(pScreen));
486    struct _WsbmListHead *list, *next;
487    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
488
489    if (!pScrn->vtSema)
490	return;
491
492    WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) {
493	struct vmwgfx_saa_pixmap *vpix =
494	    WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head);
495	struct saa_pixmap *spix = &vpix->base;
496	PixmapPtr pixmap = spix->pixmap;
497
498	if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) {
499	    REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
500	    WSBMLISTDELINIT(list);
501	}
502    }
503}
504
505
506static void
507vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap)
508{
509    ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen;
510    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
511    (void) pScreen;
512
513    vpix->backing = 0;
514    vmwgfx_pixmap_free_storage(vpix);
515
516    /*
517     * Any damage we've registered has already been removed by the server
518     * at this point. Any attempt to unregister / destroy it will result
519     * in a double free.
520     */
521
522    vmwgfx_pixmap_remove_present(vpix);
523    WSBMLISTDELINIT(&vpix->pixmap_list);
524    WSBMLISTDELINIT(&vpix->sync_x_head);
525
526    if (vpix->hw_is_dri2_fronts)
527	LogMessage(X_ERROR, "Incorrect dri2 front count.\n");
528}
529
530
531
532/**
533 *
534 * Makes sure we have a surface with valid contents.
535 */
536
537static void
538vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch,
539		   unsigned int src_pitch, unsigned int dst_height,
540		   unsigned int src_height)
541{
542    unsigned int i;
543    unsigned int height = (dst_height < src_height) ? dst_height : src_height;
544    unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch;
545
546    for(i=0; i<height; ++i) {
547	memcpy(dst, src, pitch);
548	dst += dst_pitch;
549	src += src_pitch;
550    }
551}
552
553
554static Bool
555vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch,
556		  unsigned int old_height, unsigned int old_width)
557{
558    ScreenPtr pScreen = pixmap->drawable.pScreen;
559    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
560    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
561    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
562    DrawablePtr draw = &pixmap->drawable;
563    unsigned int size = pixmap->devKind * draw->height;
564    BoxRec b_box;
565    RegionRec b_reg;
566
567    /*
568     * Ignore copying errors. At worst they will show up as rendering
569     * artefacts.
570     */
571
572    if (vpix->malloc) {
573
574	void *new_malloc = malloc(size);
575	if (!new_malloc)
576	    return FALSE;
577
578	vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind,
579			   old_pitch, draw->height,
580			   old_height);
581	free(vpix->malloc);
582	vpix->malloc = new_malloc;
583    }
584
585    if (vpix->gmr) {
586	struct vmwgfx_dmabuf *gmr;
587	void *new_addr;
588	void *old_addr;
589
590	gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
591	if (!gmr)
592	    return FALSE;
593
594	new_addr = vmwgfx_dmabuf_map(gmr);
595	old_addr = vmwgfx_dmabuf_map(vpix->gmr);
596
597	if (new_addr && old_addr)
598	    vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind,
599			       old_pitch, draw->height,
600			       old_height);
601	else
602	    LogMessage(X_ERROR, "Failed pixmap resize copy.\n");
603
604	if (old_addr)
605	    vmwgfx_dmabuf_unmap(vpix->gmr);
606	if (new_addr)
607	    vmwgfx_dmabuf_unmap(gmr);
608	vmwgfx_dmabuf_destroy(vpix->gmr);
609	vpix->gmr = gmr;
610    }
611
612    if (vpix->hw) {
613      if (!vmwgfx_xa_surface_redefine(vpix, vpix->hw, draw->width,
614				      draw->height, draw->depth, xa_type_argb,
615				      xa_format_unknown, vpix->xa_flags, 1))
616	    return FALSE;
617    }
618
619    b_box.x1 = 0;
620    b_box.x2 = draw->width;
621    b_box.y1 = 0;
622    b_box.y2 = draw->height;
623
624    REGION_INIT(pScreen, &b_reg, &b_box, 1);
625    REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow,
626		     &b_reg);
627    REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg);
628    if (vpix->dirty_present)
629	REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present,
630			 &b_reg);
631    if (vpix->pending_update)
632	REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update,
633			 &b_reg);
634    if (vpix->pending_present)
635	REGION_INTERSECT(pScreen, vpix->pending_present,
636			 vpix->pending_present, &b_reg);
637    if (vpix->present_damage)
638	REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage,
639			 &b_reg);
640
641    REGION_UNINIT(pScreen, &b_reg);
642
643    return TRUE;
644}
645
646
647static Bool
648vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth,
649			     int bpp, int devkind, void *pixdata)
650{
651    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
652    ScreenPtr pScreen = pixmap->drawable.pScreen;
653    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
654    unsigned int old_height;
655    unsigned int old_width;
656    unsigned int old_pitch;
657
658    if (!vpix) {
659	LogMessage(X_ERROR, "Not an SAA pixmap.\n");
660	return FALSE;
661    }
662
663    if (pixdata) {
664	vpix->backing = 0;
665	vmwgfx_pixmap_free_storage(vpix);
666	return FALSE;
667    }
668
669    if (depth <= 0)
670	depth = pixmap->drawable.depth;
671
672    if (bpp <= 0)
673	bpp = pixmap->drawable.bitsPerPixel;
674
675    if (w <= 0)
676	w = pixmap->drawable.width;
677
678    if (h <= 0)
679	h = pixmap->drawable.height;
680
681    if (w <= 0 || h <= 0 || depth <= 0)
682	return FALSE;
683
684    old_height = pixmap->drawable.height;
685    old_width = pixmap->drawable.width;
686    old_pitch = pixmap->devKind;
687
688    if (!miModifyPixmapHeader(pixmap, w, h, depth,
689			      bpp, devkind, NULL))
690	goto out_no_modify;
691
692    if (!vpix->backing)
693	vpix->backing = VMWGFX_PIX_MALLOC;
694
695    vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width);
696    vmwgfx_pixmap_free_storage(vpix);
697    if (WSBMLISTEMPTY(&vpix->pixmap_list))
698	WSBMLISTADDTAIL(&vpix->pixmap_list, &vsaa->pixmaps);
699
700    return TRUE;
701
702  out_no_modify:
703    return FALSE;
704}
705
706static Bool
707vmwgfx_present_prepare(struct vmwgfx_saa *vsaa,
708		       struct vmwgfx_saa_pixmap *src_vpix,
709		       struct vmwgfx_saa_pixmap *dst_vpix)
710{
711    ScreenPtr pScreen = vsaa->pScreen;
712    unsigned int dummy;
713
714    (void) pScreen;
715    if (src_vpix == dst_vpix || !src_vpix->hw ||
716	_xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0)
717	return FALSE;
718
719    REGION_NULL(pScreen, &vsaa->present_region);
720    vsaa->diff_valid = FALSE;
721    vsaa->dst_vpix = dst_vpix;
722    vsaa->present_flush(pScreen);
723
724    return TRUE;
725}
726
727/**
728 * Determine whether we should try present copies on this pixmap.
729 */
730
731static Bool
732vmwgfx_is_present_hw(PixmapPtr pixmap)
733{
734    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
735    return (vpix->dirty_present != NULL);
736}
737
738static void
739vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa,
740			 struct vmwgfx_saa_pixmap *vpix,
741			 RegionPtr region,
742			 Bool *has_dirty_hw,
743			 Bool *has_valid_hw)
744{
745    RegionRec intersection;
746
747
748    if (!vpix->hw) {
749	*has_dirty_hw = FALSE;
750	*has_valid_hw = FALSE;
751	return;
752    }
753
754    if (!region) {
755	*has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen,
756					&vpix->base.dirty_hw);
757	*has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen,
758					 &vpix->base.dirty_shadow);
759	return;
760    }
761
762    REGION_NULL(vsaa->pScreen, &intersection);
763    REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw,
764		     region);
765    *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection);
766    REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow,
767		     region);
768    *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection);
769    REGION_UNINIT(vsaa->pScreen, &intersection);
770}
771
772/**
773 * vmwgfx_prefer_gmr: Prefer a dma buffer over malloced memory for software
774 * rendered storage
775 *
776 * @vsaa: Pointer to a struct vmwgfx_saa accelerator.
777 * @pixmap: Pointer to pixmap whose storage preference we want to alter.
778 *
779 * If possible, alter the storage or future storage of the software contents
780 * of this pixmap to be in a DMA buffer rather than in malloced memory.
781 * This function should be called when it's likely that frequent DMA operations
782 * will occur between a surface and the memory holding the software
783 * contents.
784 */
785static void
786vmwgfx_prefer_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
787{
788    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
789
790    if (vsaa->can_optimize_dma) {
791	if (vpix->malloc) {
792	    (void) vmwgfx_pixmap_create_gmr(vsaa, pixmap);
793	} else if (vpix->backing & VMWGFX_PIX_MALLOC) {
794	    vpix->backing |= VMWGFX_PIX_GMR;
795	    vpix->backing &= ~VMWGFX_PIX_MALLOC;
796	}
797    }
798}
799
800Bool
801vmwgfx_create_hw(struct vmwgfx_saa *vsaa,
802		 PixmapPtr pixmap)
803{
804    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
805    struct xa_surface *hw;
806    uint32_t new_flags;
807
808    if (!vsaa->xat)
809	return FALSE;
810
811    if (vpix->hw)
812	return TRUE;
813
814    new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) |
815	vpix->staging_add_flags | XA_FLAG_SHARED;
816
817    hw = xa_surface_create(vsaa->xat,
818			   pixmap->drawable.width,
819			   pixmap->drawable.height,
820			   0,
821			   xa_type_other,
822			   vpix->staging_format,
823			   new_flags);
824    if (hw == NULL)
825	return FALSE;
826
827    vpix->xa_flags = new_flags;
828    vpix->hw = hw;
829
830    if (!vmwgfx_pixmap_add_damage(pixmap))
831	goto out_no_damage;
832
833    vpix->backing |= VMWGFX_PIX_SURFACE;
834    vmwgfx_pixmap_free_storage(vpix);
835
836    /*
837     * If there is a HW surface, make sure that the shadow is
838     * (or will be) a GMR, provided we can do fast DMAs from / to it.
839     */
840    vmwgfx_prefer_gmr(vsaa, pixmap);
841
842    return TRUE;
843
844out_no_damage:
845    vpix->hw = NULL;
846    xa_surface_destroy(hw);
847    return FALSE;
848}
849
850
851Bool
852vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region)
853{
854    struct vmwgfx_saa *vsaa =
855	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
856    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
857    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
858    RegionRec intersection;
859
860    if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region))
861	return FALSE;
862
863    REGION_NULL(vsaa->pScreen, &intersection);
864    REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow);
865
866    if (vpix->dirty_present)
867	REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present,
868		     &spix->dirty_shadow);
869
870    if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) {
871	RegionPtr upload = &intersection;
872
873	/*
874	 * Check whether we need to upload from GMR.
875	 */
876
877	if (region) {
878	    REGION_INTERSECT(vsaa->pScreen, &intersection, region,
879			     &intersection);
880	    upload = &intersection;
881	}
882
883	if (REGION_NOTEMPTY(vsaa->pScreen, upload)) {
884	    Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload);
885	    if (ret) {
886		REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow,
887				&spix->dirty_shadow, upload);
888		if (vpix->dirty_present)
889		    REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
890				    vpix->dirty_present, upload);
891	    } else {
892		REGION_UNINIT(vsaa->pScreen, &intersection);
893		return FALSE;
894	    }
895	}
896    }
897    REGION_UNINIT(vsaa->pScreen, &intersection);
898    return TRUE;
899}
900
901static Bool
902vmwgfx_copy_prepare(struct saa_driver *driver,
903		    PixmapPtr src_pixmap,
904		    PixmapPtr dst_pixmap,
905		    int dx,
906		    int dy,
907		    int alu,
908		    RegionPtr src_reg,
909		    uint32_t plane_mask)
910{
911    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
912    struct vmwgfx_saa_pixmap *src_vpix;
913    struct vmwgfx_saa_pixmap *dst_vpix;
914    Bool has_dirty_hw;
915    Bool has_valid_hw;
916
917    if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) ||
918	alu != GXcopy || !vsaa->is_master)
919	return FALSE;
920
921    src_vpix = vmwgfx_saa_pixmap(src_pixmap);
922    dst_vpix = vmwgfx_saa_pixmap(dst_pixmap);
923
924    vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg,
925			     &has_dirty_hw, &has_valid_hw);
926
927    if (vmwgfx_is_present_hw(dst_pixmap) &&
928	src_vpix->backing & VMWGFX_PIX_SURFACE) {
929
930	if (!has_dirty_hw && !has_valid_hw)
931	    return FALSE;
932
933	if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg))
934	    return FALSE;
935	if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) {
936	    vsaa->present_copy = TRUE;
937	    return TRUE;
938	}
939	return FALSE;
940    }
941
942    vsaa->present_copy = FALSE;
943    if (src_vpix != dst_vpix) {
944
945	/*
946	 * Use hardware acceleration either if source is partially only
947	 * in hardware, or if source is entirely in hardware and destination
948	 * has a hardware surface.
949	 */
950
951	if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL)))
952	    return FALSE;
953
954	/*
955	 * Determine surface formats.
956	 */
957
958	if (src_vpix->base.src_format == 0) {
959	    if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
960		return FALSE;
961	} else {
962	    if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB ||
963		!vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format))
964		return FALSE;
965	}
966
967	if (dst_vpix->base.dst_format == 0) {
968	    if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
969		return FALSE;
970	} else {
971	    if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB ||
972		!vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format))
973		return FALSE;
974	}
975
976	/*
977	 * Create hardware surfaces.
978	 */
979
980	if (!vmwgfx_hw_commit(src_pixmap))
981	    return FALSE;
982	if (!vmwgfx_hw_commit(dst_pixmap))
983	    return FALSE;
984
985	/*
986	 * Migrate data.
987	 */
988
989	if (!vmwgfx_hw_validate(src_pixmap, src_reg)) {
990	    xa_copy_done(vsaa->xa_ctx);
991	    xa_context_flush(vsaa->xa_ctx);
992	    return FALSE;
993	}
994
995	/*
996	 * Setup copy state.
997	 */
998
999	if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) !=
1000	    XA_ERR_NONE)
1001	    return FALSE;
1002
1003	return TRUE;
1004    }
1005
1006    return FALSE;
1007}
1008
1009
1010static void
1011vmwgfx_present_done(struct vmwgfx_saa *vsaa)
1012{
1013    ScreenPtr pScreen = vsaa->pScreen;
1014    struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix;
1015
1016    (void) pScreen;
1017    if (!vsaa->diff_valid)
1018	return;
1019
1020    (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id,
1021			  vsaa->xdiff, vsaa->ydiff,
1022			  &vsaa->present_region, vsaa->src_handle);
1023
1024    REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff);
1025    REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage,
1026		 &vsaa->present_region);
1027    vsaa->diff_valid = FALSE;
1028    REGION_UNINIT(pScreen, &vsaa->present_region);
1029}
1030
1031static void
1032vmwgfx_present_copy(struct vmwgfx_saa *vsaa,
1033		    int src_x,
1034		    int src_y,
1035		    int dst_x,
1036		    int dst_y,
1037		    int w,
1038		    int h)
1039{
1040    int xdiff = dst_x - src_x;
1041    int ydiff = dst_y - src_y;
1042    BoxRec box;
1043    RegionRec reg;
1044
1045    if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff)))
1046	(void) vmwgfx_present_done(vsaa);
1047
1048    if (!vsaa->diff_valid) {
1049	vsaa->xdiff = xdiff;
1050	vsaa->ydiff = ydiff;
1051	vsaa->diff_valid = TRUE;
1052    }
1053
1054    box.x1 = src_x;
1055    box.x2 = src_x + w;
1056    box.y1 = src_y;
1057    box.y2 = src_y + h;
1058
1059    REGION_INIT(pScreen, &reg, &box, 1);
1060    REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, &reg);
1061    REGION_UNINIT(pScreen, &reg);
1062}
1063
1064static void
1065vmwgfx_copy(struct saa_driver *driver,
1066	    int src_x,
1067	    int src_y,
1068	    int dst_x,
1069	    int dst_y,
1070	    int w,
1071	    int h)
1072{
1073    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1074
1075    if (vsaa->present_copy) {
1076	vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h);
1077	return;
1078    }
1079    xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h);
1080}
1081
1082static void
1083vmwgfx_copy_done(struct saa_driver *driver)
1084{
1085    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1086
1087    if (vsaa->present_copy) {
1088	vmwgfx_present_done(vsaa);
1089	return;
1090    }
1091    xa_copy_done(vsaa->xa_ctx);
1092    xa_context_flush(vsaa->xa_ctx);
1093}
1094
1095static Bool
1096vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op,
1097			 PicturePtr src_pict, PicturePtr mask_pict,
1098			 PicturePtr dst_pict,
1099			 PixmapPtr src_pix, PixmapPtr mask_pix,
1100			 PixmapPtr dst_pix,
1101			 RegionPtr src_region,
1102			 RegionPtr mask_region,
1103			 RegionPtr dst_region)
1104{
1105    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1106    struct vmwgfx_saa_pixmap *src_vpix;
1107    struct vmwgfx_saa_pixmap *dst_vpix;
1108    struct vmwgfx_saa_pixmap *mask_vpix;
1109    Bool tmp_valid_hw;
1110    Bool dirty_hw;
1111    Bool valid_hw;
1112    RegionRec empty;
1113    struct xa_composite *xa_comp;
1114
1115    if (!vsaa->is_master)
1116	return FALSE;
1117
1118    REGION_NULL(pScreen, &empty);
1119
1120    /*
1121     * First we define our migration policy. We accelerate only if there
1122     * are dirty hw regions to be read or if all source data is
1123     * available in hw, and the destination has a hardware surface.
1124     */
1125    dst_vpix = vmwgfx_saa_pixmap(dst_pix);
1126    valid_hw = (dst_vpix->hw != NULL);
1127    if (saa_op_reads_destination(op)) {
1128	vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region,
1129				 &dirty_hw, &tmp_valid_hw);
1130	valid_hw = (valid_hw && tmp_valid_hw);
1131    } else {
1132	dirty_hw = FALSE;
1133	dst_region = &empty;
1134    }
1135
1136    if (src_pix && !dirty_hw) {
1137	src_vpix = vmwgfx_saa_pixmap(src_pix);
1138	vmwgfx_check_hw_contents(vsaa, src_vpix, src_region,
1139				 &dirty_hw, &tmp_valid_hw);
1140	valid_hw = (valid_hw && tmp_valid_hw);
1141    }
1142
1143    if (mask_pict && mask_pix && !dirty_hw) {
1144	mask_vpix = vmwgfx_saa_pixmap(mask_pix);
1145	vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region,
1146				 &dirty_hw, &tmp_valid_hw);
1147	valid_hw = (valid_hw && tmp_valid_hw);
1148    }
1149
1150    /*
1151     * In rendercheck mode we try to accelerate all supported
1152     * composite operations.
1153     */
1154
1155    if (!valid_hw && !dirty_hw && !vsaa->rendercheck)
1156	goto out_err;
1157
1158    /*
1159     * Then, setup most of the XA composite state (except hardware surfaces)
1160     * and check whether XA can accelerate.
1161     */
1162
1163    if (!mask_pix)
1164	mask_pict = NULL;
1165    xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op,
1166				   src_pict, mask_pict, dst_pict);
1167    if (!xa_comp)
1168	goto out_err;
1169
1170    if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE)
1171	goto out_err;
1172
1173    /*
1174     * Check that we can create the needed hardware surfaces.
1175     */
1176    if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format))
1177	goto out_err;
1178    if (mask_pict && mask_pix &&
1179	!vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format))
1180	goto out_err;
1181    if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format))
1182	goto out_err;
1183
1184    /*
1185     * Seems OK. Commit the changes, creating hardware surfaces.
1186     */
1187    if (src_pix && !vmwgfx_hw_commit(src_pix))
1188	goto out_err;
1189    if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix))
1190	goto out_err;
1191    if (!vmwgfx_hw_commit(dst_pix))
1192	goto out_err;
1193
1194    /*
1195     * Update the XA state with our hardware surfaces and
1196     * surface formats
1197     */
1198    if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix))
1199	goto out_err;
1200
1201    /*
1202     * Migrate data to surfaces.
1203     */
1204    if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL))
1205	goto out_err;
1206    if (mask_pict && mask_pix && mask_region &&
1207	!vmwgfx_hw_validate(mask_pix, NULL))
1208	goto out_err;
1209    if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL))
1210	goto out_err;
1211
1212
1213    /*
1214     * Bind the XA state. This must be done after data migration, since
1215     * migration may change the hardware surfaces.
1216     */
1217    if (xa_composite_prepare(vsaa->xa_ctx, xa_comp))
1218	goto out_err;
1219
1220    return TRUE;
1221
1222  out_err:
1223    return FALSE;
1224}
1225
1226static void
1227vmwgfx_composite(struct saa_driver *driver,
1228		 int src_x, int src_y, int mask_x, int mask_y,
1229		 int dst_x, int dst_y,
1230		 int width, int height)
1231{
1232    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1233
1234    xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y,
1235		      dst_x, dst_y, width, height);
1236}
1237
1238static void
1239vmwgfx_composite_done(struct saa_driver *driver)
1240{
1241   struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1242
1243   xa_composite_done(vsaa->xa_ctx);
1244   xa_context_flush(vsaa->xa_ctx);
1245}
1246
1247static void
1248vmwgfx_takedown(struct saa_driver *driver)
1249{
1250    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1251
1252    if (vsaa->vcomp)
1253	vmwgfx_free_composite(vsaa->vcomp);
1254    free(vsaa);
1255}
1256
1257/*
1258 * This function call originates from the damage layer (outside SAA)
1259 * to indicate that an operation is complete, and that damage is being
1260 * processed.
1261 */
1262static void
1263vmwgfx_operation_complete(struct saa_driver *driver,
1264			  PixmapPtr pixmap)
1265{
1266    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1267    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
1268    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
1269    ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen);
1270
1271    /*
1272     * Make dri2 drawables up to date, or add them to the flush list
1273     * executed at glxWaitX(). Currently glxWaitX() is broken, so
1274     * we flush immediately, unless we're VT-switched away, in which
1275     * case a flush would deadlock in the kernel.
1276     *
1277     * For pixmaps for which vpix->hw_is_hosted is true, we can explicitly
1278     * inform the compositor when contents has changed, so for those pixmaps
1279     * we defer the upload until the compositor is informed, by putting
1280     * them on the sync_x_list. Note that hw_is_dri2_fronts take precedence.
1281     */
1282    if (vpix->hw && (vpix->hw_is_dri2_fronts || vpix->hw_is_hosted)) {
1283	if (pScrn->vtSema && vpix->hw_is_dri2_fronts &&
1284	    vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) {
1285
1286	    REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
1287	    return;
1288	}
1289
1290	if (WSBMLISTEMPTY(&vpix->sync_x_head))
1291	    WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list);
1292    }
1293}
1294
1295/*
1296 * This function is called by SAA to indicate that SAA has
1297 * dirtied a region of a pixmap, either as hw (accelerated) or as
1298 * !hw (not accelerated).
1299 */
1300static Bool
1301vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap,
1302	     Bool hw, RegionPtr damage)
1303{
1304    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1305    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
1306    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
1307
1308    /*
1309     * Return if this is not a scanout pixmap.
1310     */
1311    if (WSBMLISTEMPTY(&vpix->scanout_list))
1312	return TRUE;
1313
1314#if 0
1315    /*
1316     * This code can be enabled to immediately upload scanout sw
1317     * contents to the hw surface. Otherwise this is done
1318     * just before we call the kms update function for the hw
1319     * surface.
1320     */
1321    if (vsaa->only_hw_presents) {
1322	if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage))
1323	    return FALSE;
1324
1325	REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow,
1326			&spix->dirty_shadow, damage);
1327	hw = TRUE;
1328    }
1329#endif
1330
1331    /*
1332     * Is the new scanout damage hw or sw?
1333     */
1334    if (hw) {
1335	/*
1336	 * Dump pending present into present tracking region.
1337	 */
1338	if (vpix->dirty_present &&
1339	    REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) {
1340	    REGION_UNION(vsaa->pScreen, vpix->dirty_present,
1341			 vpix->dirty_present, damage);
1342	    REGION_EMPTY(vsaa->pScreen, vpix->present_damage);
1343	} else {
1344	    if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) {
1345		RegionRec reg;
1346
1347		REGION_NULL(vsaa->pScreen, &reg);
1348		REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_update,
1349				 damage);
1350		if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
1351		    vsaa->present_flush(vsaa->pScreen);
1352		REGION_UNINIT(pScreen, &reg);
1353	    }
1354	    REGION_UNION(vsaa->pScreen, vpix->pending_present,
1355			 vpix->pending_present, damage);
1356	    if (vpix->dirty_present)
1357		REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
1358				vpix->dirty_present, damage);
1359	}
1360    } else {
1361	    if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) {
1362		RegionRec reg;
1363
1364		REGION_NULL(vsaa->pScreen, &reg);
1365		REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_present,
1366				 damage);
1367		if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
1368		    vsaa->present_flush(vsaa->pScreen);
1369		REGION_UNINIT(pScreen, &reg);
1370	    }
1371	    REGION_UNION(vsaa->pScreen, vpix->pending_update,
1372			 vpix->pending_update, damage);
1373	    if (vpix->dirty_present)
1374		REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
1375				vpix->dirty_present, damage);
1376    }
1377
1378    return TRUE;
1379}
1380
1381
1382static const struct saa_driver vmwgfx_saa_driver = {
1383    .saa_major = SAA_VERSION_MAJOR,
1384    .saa_minor = SAA_VERSION_MINOR,
1385    .pixmap_size = sizeof(struct vmwgfx_saa_pixmap),
1386    .damage = vmwgfx_dirty,
1387    .operation_complete = vmwgfx_operation_complete,
1388    .download_from_hw = vmwgfx_download_from_hw,
1389    .release_from_cpu = vmwgfx_release_from_cpu,
1390    .sync_for_cpu = vmwgfx_sync_for_cpu,
1391    .map = vmwgfx_map,
1392    .unmap = vmwgfx_unmap,
1393    .create_pixmap = vmwgfx_create_pixmap,
1394    .destroy_pixmap = vmwgfx_destroy_pixmap,
1395    .modify_pixmap_header = vmwgfx_modify_pixmap_header,
1396    .copy_prepare = vmwgfx_copy_prepare,
1397    .copy = vmwgfx_copy,
1398    .copy_done = vmwgfx_copy_done,
1399    .composite_prepare = vmwgfx_composite_prepare,
1400    .composite = vmwgfx_composite,
1401    .composite_done = vmwgfx_composite_done,
1402    .takedown = vmwgfx_takedown,
1403};
1404
1405
1406Bool
1407vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
1408		void (*present_flush)(ScreenPtr pScreen),
1409		Bool direct_presents,
1410		Bool only_hw_presents,
1411		Bool rendercheck)
1412{
1413    struct vmwgfx_saa *vsaa;
1414
1415    vsaa = calloc(1, sizeof(*vsaa));
1416    if (!vsaa)
1417	return FALSE;
1418
1419    if (xat == NULL) {
1420	direct_presents = FALSE;
1421	only_hw_presents = FALSE;
1422    }
1423
1424    vsaa->pScreen = pScreen;
1425    vsaa->xat = xat;
1426    if (xat)
1427	vsaa->xa_ctx = xa_context_default(xat);
1428    vsaa->drm_fd = drm_fd;
1429    vsaa->present_flush = present_flush;
1430    vsaa->can_optimize_dma = TRUE;
1431    vsaa->use_present_opt = direct_presents;
1432    vsaa->only_hw_presents = only_hw_presents;
1433    vsaa->rendercheck = rendercheck;
1434    vsaa->is_master = TRUE;
1435    vsaa->known_prime_format = FALSE;
1436    WSBMINITLISTHEAD(&vsaa->sync_x_list);
1437    WSBMINITLISTHEAD(&vsaa->pixmaps);
1438
1439    vsaa->driver = vmwgfx_saa_driver;
1440    vsaa->vcomp = vmwgfx_alloc_composite();
1441
1442    if (!vsaa->vcomp)
1443	vsaa->driver.composite_prepare = NULL;
1444
1445    if (!saa_driver_init(pScreen, &vsaa->driver))
1446	goto out_no_saa;
1447
1448    return TRUE;
1449  out_no_saa:
1450    free(vsaa);
1451    return FALSE;
1452}
1453
1454/*
1455 * *************************************************************************
1456 * Scanout functions.
1457 * These do not strictly belong here, but we choose to hide the scanout
1458 * pixmap private data in the saa pixmaps. Might want to revisit this.
1459 */
1460
1461/*
1462 * Make sure we flush / update this scanout on next update run.
1463 */
1464
1465void
1466vmwgfx_scanout_refresh(PixmapPtr pixmap)
1467{
1468    ScreenPtr pScreen = pixmap->drawable.pScreen;
1469    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
1470    BoxRec box;
1471
1472    (void) pScreen;
1473    box.x1 = 0;
1474    box.y1 = 0;
1475    box.x2 = pixmap->drawable.width;
1476    box.y2 = pixmap->drawable.height;
1477
1478    REGION_RESET(vsaa->pScreen, vpix->pending_present, &box);
1479    if (vpix->dirty_present)
1480	REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
1481			vpix->pending_present, vpix->dirty_present);
1482    REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
1483		    vpix->pending_present, &vpix->base.dirty_shadow);
1484    REGION_COPY(vsaa->pScreen, vpix->pending_update,
1485		&vpix->base.dirty_shadow);
1486}
1487
1488/*
1489 * Take a "scanout reference" on a pixmap. If this is the first scanout
1490 * reference, allocate resources needed for scanout, like proper
1491 * damage tracking and kms fbs.
1492 */
1493
1494uint32_t
1495vmwgfx_scanout_ref(struct vmwgfx_screen_entry  *entry)
1496{
1497    PixmapPtr pixmap = entry->pixmap;
1498    struct vmwgfx_saa *vsaa =
1499	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
1500    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
1501
1502    if (WSBMLISTEMPTY(&vpix->scanout_list)) {
1503	uint32_t handle, dummy;
1504	unsigned int depth;
1505
1506	if (vsaa->only_hw_presents) {
1507	    /*
1508	     * The KMS fb will be a HW surface. Create it, add damage
1509	     * and get the handle.
1510	     */
1511	    if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT |
1512					  XA_FLAG_RENDER_TARGET, 0, NULL))
1513		goto out_err;
1514	    if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0)
1515		goto out_err;
1516	    depth = xa_format_depth(xa_surface_format(vpix->hw));
1517
1518	} else {
1519	    /*
1520	     * The KMS fb will be a Guest Memory Region. Create it,
1521	     * add damage and get the handle.
1522	     */
1523	    if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
1524		goto out_err;
1525
1526	    handle = vpix->gmr->handle;
1527	    depth = pixmap->drawable.depth;
1528
1529	}
1530
1531        if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt))
1532	    goto out_no_present;
1533
1534	if (drmModeAddFB(vsaa->drm_fd,
1535			 pixmap->drawable.width,
1536			 pixmap->drawable.height,
1537			 depth,
1538			 pixmap->drawable.bitsPerPixel,
1539			 pixmap->devKind,
1540			 handle,
1541			 &vpix->fb_id) != 0)
1542	    goto out_no_fb;;
1543    }
1544    pixmap->refcnt += 1;
1545    WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list);
1546    return vpix->fb_id;
1547
1548  out_no_fb:
1549    vmwgfx_pixmap_remove_present(vpix);
1550  out_no_present:
1551    vmwgfx_pixmap_remove_damage(pixmap);
1552  out_err:
1553    vpix->fb_id = -1;
1554    return -1;
1555}
1556
1557/*
1558 * Free a "scanout reference" on a pixmap. If this was the last scanout
1559 * reference, free pixmap resources needed for scanout, like
1560 * damage tracking and kms fbs.
1561 */
1562void
1563vmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry)
1564{
1565    struct vmwgfx_saa *vsaa;
1566    struct vmwgfx_saa_pixmap *vpix;
1567    PixmapPtr pixmap = entry->pixmap;
1568
1569    if (!pixmap)
1570	return;
1571
1572    vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
1573    vpix = vmwgfx_saa_pixmap(pixmap);
1574    WSBMLISTDELINIT(&entry->scanout_head);
1575
1576    if (WSBMLISTEMPTY(&vpix->scanout_list)) {
1577	REGION_EMPTY(vsaa->pScreen, vpix->pending_update);
1578	drmModeRmFB(vsaa->drm_fd, vpix->fb_id);
1579	vpix->fb_id = -1;
1580	vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL);
1581	vmwgfx_pixmap_remove_present(vpix);
1582	vmwgfx_pixmap_remove_damage(pixmap);
1583    }
1584
1585    entry->pixmap = NULL;
1586    pixmap->drawable.pScreen->DestroyPixmap(pixmap);
1587}
1588
1589void
1590vmwgfx_saa_set_master(ScreenPtr pScreen)
1591{
1592    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
1593
1594    vsaa->is_master = TRUE;
1595    vmwgfx_flush_dri2(pScreen);
1596}
1597
1598void
1599vmwgfx_saa_drop_master(ScreenPtr pScreen)
1600{
1601    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
1602    struct _WsbmListHead *list;
1603    struct vmwgfx_saa_pixmap *vpix;
1604    struct saa_pixmap *spix;
1605
1606    WSBMLISTFOREACH(list, &vsaa->pixmaps) {
1607	vpix = WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, pixmap_list);
1608	spix = &vpix->base;
1609
1610	if (!vpix->hw)
1611	    continue;
1612
1613	(void) vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
1614				       &spix->dirty_hw);
1615	REGION_EMPTY(draw->pScreen, &spix->dirty_hw);
1616    }
1617
1618    vsaa->is_master = FALSE;
1619}
1620
1621/*
1622 * *************************************************************************
1623 * Helpers for hosted.
1624 */
1625
1626#if (XA_TRACKER_VERSION_MAJOR >= 2) && defined(HAVE_LIBDRM_2_4_38)
1627
1628/**
1629 * vmwgfx_saa_copy_to_surface - Copy Drawable contents to an external surface.
1630 *
1631 * @pDraw: Pointer to source drawable.
1632 * @surface_fd: Prime file descriptor of external surface to copy to.
1633 * @dst_box: BoxRec describing the destination bounding box.
1634 * @region: Region of drawable to copy. Note: The code assumes that the
1635 * region is relative to the drawable origin, not the underlying pixmap
1636 * origin.
1637 *
1638 * Copies the contents (both software- and accelerated contents) to an
1639 * external surface.
1640 */
1641Bool
1642vmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd,
1643			   const BoxRec *dst_box, RegionPtr region)
1644{
1645    ScreenPtr pScreen = pDraw->pScreen;
1646    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
1647    PixmapPtr src;
1648    struct saa_pixmap *spix;
1649    struct vmwgfx_saa_pixmap *vpix;
1650    const BoxRec *box;
1651    int n;
1652    int sx, sy, dx, dy;
1653    struct xa_surface *dst;
1654    uint32_t handle;
1655    Bool ret = TRUE;
1656    RegionRec intersection;
1657    RegionPtr copy_region = region;
1658
1659    if (vmwgfx_prime_fd_to_handle(vsaa->drm_fd, surface_fd, &handle) < 0)
1660	return FALSE;
1661
1662    dst = xa_surface_from_handle(vsaa->xat, pDraw->width, pDraw->height,
1663				 pDraw->depth, xa_type_argb,
1664				 xa_format_unknown,
1665				 XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
1666				 handle,
1667				 (pDraw->width * pDraw->bitsPerPixel + 7) / 8);
1668
1669    if (!dst) {
1670	ret = FALSE;
1671	goto out_no_surface;
1672    }
1673
1674    /*
1675     * Assume damage region is relative to the source window.
1676     */
1677    src = saa_get_pixmap(pDraw, &sx, &sy);
1678    sx += pDraw->x;
1679    sy += pDraw->y;
1680    if (sx || sy)
1681	REGION_TRANSLATE(pScreen, region, sx, sy);
1682
1683    dx = dst_box->x1 - sx;
1684    dy = dst_box->y1 - sy;
1685
1686    spix = saa_get_saa_pixmap(src);
1687    vpix = to_vmwgfx_saa_pixmap(spix);
1688
1689    /*
1690     * Make sure software contents of the source pixmap is henceforth put
1691     * in a GMR to avoid the extra copy in the xa DMA.
1692     */
1693    vmwgfx_prefer_gmr(vsaa, src);
1694
1695    /*
1696     * Determine the intersection between software contents and region to copy.
1697     */
1698
1699    if (vsaa->known_prime_format) {
1700	REGION_NULL(pScreen, &intersection);
1701	if (!vpix->hw)
1702	    REGION_COPY(pScreen, &intersection, region);
1703	else if (spix->damage && REGION_NOTEMPTY(pScreen, &spix->dirty_shadow))
1704	    REGION_INTERSECT(pScreen, &intersection, region, &spix->dirty_shadow);
1705
1706	/*
1707	 * DMA software contents directly into the destination. Then subtract
1708	 * the region we've DMA'd from the region to copy.
1709	 */
1710	if (REGION_NOTEMPTY(pScreen, &intersection)) {
1711	    if (vmwgfx_saa_dma(vsaa, src, &intersection, TRUE, dx, dy, dst)) {
1712		REGION_SUBTRACT(pScreen, &intersection, region, &intersection);
1713		copy_region = &intersection;
1714	    }
1715	}
1716    }
1717
1718    if (!REGION_NOTEMPTY(pScreen, copy_region))
1719	goto out_no_copy;
1720
1721    /*
1722     * Copy Hardware contents to the destination
1723     */
1724    box = REGION_RECTS(copy_region);
1725    n = REGION_NUM_RECTS(copy_region);
1726
1727    if (!vmwgfx_hw_accel_validate(src, 0, 0, 0, copy_region)) {
1728	ret = FALSE;
1729	goto out_no_copy;
1730    }
1731
1732    if (xa_copy_prepare(vsaa->xa_ctx, dst, vpix->hw) != XA_ERR_NONE) {
1733	ret = FALSE;
1734	goto out_no_copy;
1735    }
1736
1737    while(n--) {
1738	xa_copy(vsaa->xa_ctx, box->x1 + dx, box->y1 + dy, box->x1, box->y1,
1739		box->x2 - box->x1, box->y2 - box->y1);
1740	box++;
1741    }
1742
1743    xa_copy_done(vsaa->xa_ctx);
1744    xa_context_flush(vsaa->xa_ctx);
1745
1746  out_no_copy:
1747    if (vsaa->known_prime_format)
1748	REGION_UNINIT(pScreen, &intersection);
1749    if (sx || sy)
1750	REGION_TRANSLATE(pScreen, region, -sx, -sy);
1751    xa_surface_unref(dst);
1752  out_no_surface:
1753    vmwgfx_prime_release_handle(vsaa->drm_fd, handle);
1754
1755    return ret;
1756}
1757#endif
1758