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  */
41 static Bool
vmwgfx_pixmap_add_damage(PixmapPtr pixmap)42 vmwgfx_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 
71 static void
vmwgfx_pixmap_remove_damage(PixmapPtr pixmap)72 vmwgfx_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 
90 static void
vmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap * vpix)91 vmwgfx_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 
107 static Bool
vmwgfx_pixmap_add_present(PixmapPtr pixmap,Bool present_opt)108 vmwgfx_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 
141 static void
vmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap * vpix)142 vmwgfx_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 
158 static Bool
vmwgfx_pixmap_create_gmr(struct vmwgfx_saa * vsaa,PixmapPtr pixmap)159 vmwgfx_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 
198 static Bool
vmwgfx_pixmap_create_sw(struct vmwgfx_saa * vsaa,PixmapPtr pixmap)199 vmwgfx_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 
231 static Bool
vmwgfx_pixmap_present_readback(struct vmwgfx_saa * vsaa,PixmapPtr pixmap,RegionPtr region)232 vmwgfx_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 
281 static Bool
vmwgfx_saa_dma(struct vmwgfx_saa * vsaa,PixmapPtr pixmap,RegionPtr reg,Bool to_hw,int dx,int dy,struct xa_surface * srf)282 vmwgfx_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 
343 static Bool
vmwgfx_download_from_hw(struct saa_driver * driver,PixmapPtr pixmap,RegionPtr readback)344 vmwgfx_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 
375     return TRUE;
376  out_err:
377     REGION_UNINIT(vsaa->pScreen, &intersection);
378     return FALSE;
379 }
380 
381 
382 static Bool
vmwgfx_upload_to_hw(struct saa_driver * driver,PixmapPtr pixmap,RegionPtr upload)383 vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap,
384 		    RegionPtr upload)
385 {
386     return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE,
387 			  0, 0, NULL);
388 }
389 
390 static void
vmwgfx_release_from_cpu(struct saa_driver * driver,PixmapPtr pixmap,saa_access_t access)391 vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
392 {
393   //    LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n",
394   //	       (unsigned long) pixmap, (unsigned) access);
395 }
396 
397 static void *
vmwgfx_sync_for_cpu(struct saa_driver * driver,PixmapPtr pixmap,saa_access_t access)398 vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
399 {
400     /*
401      * Errors in this functions will turn up in subsequent map
402      * calls.
403      */
404 
405     (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap);
406 
407     return NULL;
408 }
409 
410 static void *
vmwgfx_map(struct saa_driver * driver,PixmapPtr pixmap,saa_access_t access)411 vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
412 {
413     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
414 
415     if (vpix->malloc)
416 	return vpix->malloc;
417     else if (vpix->gmr)
418 	return vmwgfx_dmabuf_map(vpix->gmr);
419     else
420 	return NULL;
421 }
422 
423 static void
vmwgfx_unmap(struct saa_driver * driver,PixmapPtr pixmap,saa_access_t access)424 vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
425 {
426     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
427 
428     if (vpix->gmr)
429 	return vmwgfx_dmabuf_unmap(vpix->gmr);
430 
431 //    LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n",
432     //       (unsigned long) pixmap, (unsigned) access);
433     ;
434 }
435 
436 static Bool
vmwgfx_create_pixmap(struct saa_driver * driver,struct saa_pixmap * spix,int w,int h,int depth,unsigned int usage_hint,int bpp,int * new_pitch)437 vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix,
438 		     int w, int h, int depth,
439 		     unsigned int usage_hint, int bpp, int *new_pitch)
440 {
441     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
442 
443     *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
444 
445     WSBMINITLISTHEAD(&vpix->sync_x_head);
446     WSBMINITLISTHEAD(&vpix->scanout_list);
447     WSBMINITLISTHEAD(&vpix->pixmap_list);
448 
449     return TRUE;
450 }
451 
452 Bool
vmwgfx_hw_kill(struct vmwgfx_saa * vsaa,struct saa_pixmap * spix)453 vmwgfx_hw_kill(struct vmwgfx_saa *vsaa,
454 	       struct saa_pixmap *spix)
455 {
456     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
457 
458     if (!vpix->hw)
459 	return TRUE;
460 
461     /*
462      * Read back any dirty regions from hardware.
463      */
464 
465     if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
466 				 &spix->dirty_hw))
467 	return FALSE;
468 
469     xa_surface_destroy(vpix->hw);
470     vpix->hw = NULL;
471 
472     /*
473      * Remove damage tracking if this is not a scanout pixmap.
474      */
475 
476     if (WSBMLISTEMPTY(&vpix->scanout_list))
477 	vmwgfx_pixmap_remove_damage(spix->pixmap);
478 
479     return TRUE;
480 }
481 
482 void
vmwgfx_flush_dri2(ScreenPtr pScreen)483 vmwgfx_flush_dri2(ScreenPtr pScreen)
484 {
485     struct vmwgfx_saa *vsaa =
486 	to_vmwgfx_saa(saa_get_driver(pScreen));
487     struct _WsbmListHead *list, *next;
488     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
489 
490     if (!pScrn->vtSema)
491 	return;
492 
493     WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) {
494 	struct vmwgfx_saa_pixmap *vpix =
495 	    WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head);
496 	struct saa_pixmap *spix = &vpix->base;
497 	PixmapPtr pixmap = spix->pixmap;
498 
499 	if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) {
500 	    REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
501 	    WSBMLISTDELINIT(list);
502 	}
503     }
504 }
505 
506 
507 static void
vmwgfx_destroy_pixmap(struct saa_driver * driver,PixmapPtr pixmap)508 vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap)
509 {
510     ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen;
511     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
512     (void) pScreen;
513 
514     vpix->backing = 0;
515     vmwgfx_pixmap_free_storage(vpix);
516 
517     /*
518      * Any damage we've registered has already been removed by the server
519      * at this point. Any attempt to unregister / destroy it will result
520      * in a double free.
521      */
522 
523     vmwgfx_pixmap_remove_present(vpix);
524     WSBMLISTDELINIT(&vpix->pixmap_list);
525     WSBMLISTDELINIT(&vpix->sync_x_head);
526 }
527 
528 
529 
530 /**
531  *
532  * Makes sure we have a surface with valid contents.
533  */
534 
535 static void
vmwgfx_copy_stride(uint8_t * dst,uint8_t * src,unsigned int dst_pitch,unsigned int src_pitch,unsigned int dst_height,unsigned int src_height)536 vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch,
537 		   unsigned int src_pitch, unsigned int dst_height,
538 		   unsigned int src_height)
539 {
540     unsigned int i;
541     unsigned int height = (dst_height < src_height) ? dst_height : src_height;
542     unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch;
543 
544     for(i=0; i<height; ++i) {
545 	memcpy(dst, src, pitch);
546 	dst += dst_pitch;
547 	src += src_pitch;
548     }
549 }
550 
551 
552 static Bool
vmwgfx_pix_resize(PixmapPtr pixmap,unsigned int old_pitch,unsigned int old_height,unsigned int old_width)553 vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch,
554 		  unsigned int old_height, unsigned int old_width)
555 {
556     ScreenPtr pScreen = pixmap->drawable.pScreen;
557     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
558     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
559     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
560     DrawablePtr draw = &pixmap->drawable;
561     unsigned int size = pixmap->devKind * draw->height;
562     BoxRec b_box;
563     RegionRec b_reg;
564 
565     /*
566      * Ignore copying errors. At worst they will show up as rendering
567      * artefacts.
568      */
569 
570     if (vpix->malloc) {
571 
572 	void *new_malloc = malloc(size);
573 	if (!new_malloc)
574 	    return FALSE;
575 
576 	vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind,
577 			   old_pitch, draw->height,
578 			   old_height);
579 	free(vpix->malloc);
580 	vpix->malloc = new_malloc;
581     }
582 
583     if (vpix->gmr) {
584 	struct vmwgfx_dmabuf *gmr;
585 	void *new_addr;
586 	void *old_addr;
587 
588 	gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
589 	if (!gmr)
590 	    return FALSE;
591 
592 	new_addr = vmwgfx_dmabuf_map(gmr);
593 	old_addr = vmwgfx_dmabuf_map(vpix->gmr);
594 
595 	if (new_addr && old_addr)
596 	    vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind,
597 			       old_pitch, draw->height,
598 			       old_height);
599 	else
600 	    LogMessage(X_ERROR, "Failed pixmap resize copy.\n");
601 
602 	if (old_addr)
603 	    vmwgfx_dmabuf_unmap(vpix->gmr);
604 	if (new_addr)
605 	    vmwgfx_dmabuf_unmap(gmr);
606 	vmwgfx_dmabuf_destroy(vpix->gmr);
607 	vpix->gmr = gmr;
608     }
609 
610     if (vpix->hw) {
611       if (!vmwgfx_xa_surface_redefine(vpix, vpix->hw, draw->width,
612 				      draw->height, draw->depth, xa_type_argb,
613 				      xa_format_unknown, vpix->xa_flags, 1))
614 	    return FALSE;
615     }
616 
617     b_box.x1 = 0;
618     b_box.x2 = draw->width;
619     b_box.y1 = 0;
620     b_box.y2 = draw->height;
621 
622     REGION_INIT(pScreen, &b_reg, &b_box, 1);
623     REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow,
624 		     &b_reg);
625     REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg);
626     if (vpix->dirty_present)
627 	REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present,
628 			 &b_reg);
629     if (vpix->pending_update)
630 	REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update,
631 			 &b_reg);
632     if (vpix->pending_present)
633 	REGION_INTERSECT(pScreen, vpix->pending_present,
634 			 vpix->pending_present, &b_reg);
635     if (vpix->present_damage)
636 	REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage,
637 			 &b_reg);
638 
639     REGION_UNINIT(pScreen, &b_reg);
640 
641     return TRUE;
642 }
643 
644 
645 static Bool
vmwgfx_modify_pixmap_header(PixmapPtr pixmap,int w,int h,int depth,int bpp,int devkind,void * pixdata)646 vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth,
647 			     int bpp, int devkind, void *pixdata)
648 {
649     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
650     ScreenPtr pScreen = pixmap->drawable.pScreen;
651     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
652     unsigned int old_height;
653     unsigned int old_width;
654     unsigned int old_pitch;
655 
656     if (!vpix) {
657 	LogMessage(X_ERROR, "Not an SAA pixmap.\n");
658 	return FALSE;
659     }
660 
661     if (pixdata) {
662 	vpix->backing = 0;
663 	vmwgfx_pixmap_free_storage(vpix);
664 	return FALSE;
665     }
666 
667     if (depth <= 0)
668 	depth = pixmap->drawable.depth;
669 
670     if (bpp <= 0)
671 	bpp = pixmap->drawable.bitsPerPixel;
672 
673     if (w <= 0)
674 	w = pixmap->drawable.width;
675 
676     if (h <= 0)
677 	h = pixmap->drawable.height;
678 
679     if (w <= 0 || h <= 0 || depth <= 0)
680 	return FALSE;
681 
682     old_height = pixmap->drawable.height;
683     old_width = pixmap->drawable.width;
684     old_pitch = pixmap->devKind;
685 
686     if (!miModifyPixmapHeader(pixmap, w, h, depth,
687 			      bpp, devkind, NULL))
688 	goto out_no_modify;
689 
690     if (!vpix->backing)
691 	vpix->backing = VMWGFX_PIX_MALLOC;
692 
693     vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width);
694     vmwgfx_pixmap_free_storage(vpix);
695     if (WSBMLISTEMPTY(&vpix->pixmap_list))
696 	WSBMLISTADDTAIL(&vpix->pixmap_list, &vsaa->pixmaps);
697 
698     return TRUE;
699 
700   out_no_modify:
701     return FALSE;
702 }
703 
704 static Bool
vmwgfx_present_prepare(struct vmwgfx_saa * vsaa,struct vmwgfx_saa_pixmap * src_vpix,struct vmwgfx_saa_pixmap * dst_vpix)705 vmwgfx_present_prepare(struct vmwgfx_saa *vsaa,
706 		       struct vmwgfx_saa_pixmap *src_vpix,
707 		       struct vmwgfx_saa_pixmap *dst_vpix)
708 {
709     ScreenPtr pScreen = vsaa->pScreen;
710     unsigned int dummy;
711 
712     (void) pScreen;
713     if (src_vpix == dst_vpix || !src_vpix->hw ||
714 	_xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0)
715 	return FALSE;
716 
717     REGION_NULL(pScreen, &vsaa->present_region);
718     vsaa->diff_valid = FALSE;
719     vsaa->dst_vpix = dst_vpix;
720     vsaa->present_flush(pScreen);
721 
722     return TRUE;
723 }
724 
725 /**
726  * Determine whether we should try present copies on this pixmap.
727  */
728 
729 static Bool
vmwgfx_is_present_hw(PixmapPtr pixmap)730 vmwgfx_is_present_hw(PixmapPtr pixmap)
731 {
732     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
733     return (vpix->dirty_present != NULL);
734 }
735 
736 static void
vmwgfx_check_hw_contents(struct vmwgfx_saa * vsaa,struct vmwgfx_saa_pixmap * vpix,RegionPtr region,Bool * has_dirty_hw,Bool * has_valid_hw)737 vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa,
738 			 struct vmwgfx_saa_pixmap *vpix,
739 			 RegionPtr region,
740 			 Bool *has_dirty_hw,
741 			 Bool *has_valid_hw)
742 {
743     RegionRec intersection;
744 
745 
746     if (!vpix->hw) {
747 	*has_dirty_hw = FALSE;
748 	*has_valid_hw = FALSE;
749 	return;
750     }
751 
752     if (!region) {
753 	*has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen,
754 					&vpix->base.dirty_hw);
755 	*has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen,
756 					 &vpix->base.dirty_shadow);
757 	return;
758     }
759 
760     REGION_NULL(vsaa->pScreen, &intersection);
761     REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw,
762 		     region);
763     *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection);
764     REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow,
765 		     region);
766     *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection);
767     REGION_UNINIT(vsaa->pScreen, &intersection);
768 }
769 
770 /**
771  * vmwgfx_prefer_gmr: Prefer a dma buffer over malloced memory for software
772  * rendered storage
773  *
774  * @vsaa: Pointer to a struct vmwgfx_saa accelerator.
775  * @pixmap: Pointer to pixmap whose storage preference we want to alter.
776  *
777  * If possible, alter the storage or future storage of the software contents
778  * of this pixmap to be in a DMA buffer rather than in malloced memory.
779  * This function should be called when it's likely that frequent DMA operations
780  * will occur between a surface and the memory holding the software
781  * contents.
782  */
783 static void
vmwgfx_prefer_gmr(struct vmwgfx_saa * vsaa,PixmapPtr pixmap)784 vmwgfx_prefer_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
785 {
786     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
787 
788     if (vsaa->can_optimize_dma) {
789 	if (vpix->malloc) {
790 	    (void) vmwgfx_pixmap_create_gmr(vsaa, pixmap);
791 	} else if (vpix->backing & VMWGFX_PIX_MALLOC) {
792 	    vpix->backing |= VMWGFX_PIX_GMR;
793 	    vpix->backing &= ~VMWGFX_PIX_MALLOC;
794 	}
795     }
796 }
797 
798 Bool
vmwgfx_create_hw(struct vmwgfx_saa * vsaa,PixmapPtr pixmap,Bool shared)799 vmwgfx_create_hw(struct vmwgfx_saa *vsaa,
800 		 PixmapPtr pixmap,
801 		 Bool shared)
802 {
803     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
804     struct xa_surface *hw;
805     uint32_t new_flags;
806 
807     if (!vsaa->xat)
808 	return FALSE;
809 
810     if (!shared) {
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     } else {
825 	new_flags = vpix->xa_flags;
826 	hw = vpix->hw;
827     }
828 
829     if (hw == NULL)
830 	return FALSE;
831 
832     vpix->xa_flags = new_flags;
833     vpix->hw = hw;
834 
835     if (!vmwgfx_pixmap_add_damage(pixmap))
836 	goto out_no_damage;
837 
838     vpix->backing |= VMWGFX_PIX_SURFACE;
839     vmwgfx_pixmap_free_storage(vpix);
840 
841     /*
842      * If there is a HW surface, make sure that the shadow is
843      * (or will be) a GMR, provided we can do fast DMAs from / to it.
844      */
845     vmwgfx_prefer_gmr(vsaa, pixmap);
846 
847     return TRUE;
848 
849 out_no_damage:
850     vpix->hw = NULL;
851     xa_surface_destroy(hw);
852     return FALSE;
853 }
854 
855 
856 Bool
vmwgfx_hw_validate(PixmapPtr pixmap,RegionPtr region)857 vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region)
858 {
859     struct vmwgfx_saa *vsaa =
860 	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
861     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
862     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
863     RegionRec intersection;
864 
865     if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region))
866 	return FALSE;
867 
868     REGION_NULL(vsaa->pScreen, &intersection);
869     REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow);
870 
871     if (vpix->dirty_present)
872 	REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present,
873 		     &spix->dirty_shadow);
874 
875     if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) {
876 	RegionPtr upload = &intersection;
877 
878 	/*
879 	 * Check whether we need to upload from GMR.
880 	 */
881 
882 	if (region) {
883 	    REGION_INTERSECT(vsaa->pScreen, &intersection, region,
884 			     &intersection);
885 	    upload = &intersection;
886 	}
887 
888 	if (REGION_NOTEMPTY(vsaa->pScreen, upload)) {
889 	    Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload);
890 	    if (ret) {
891 		REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow,
892 				&spix->dirty_shadow, upload);
893 		if (vpix->dirty_present)
894 		    REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
895 				    vpix->dirty_present, upload);
896 	    } else {
897 		REGION_UNINIT(vsaa->pScreen, &intersection);
898 		return FALSE;
899 	    }
900 	}
901     }
902     REGION_UNINIT(vsaa->pScreen, &intersection);
903     return TRUE;
904 }
905 
906 static Bool
vmwgfx_copy_prepare(struct saa_driver * driver,PixmapPtr src_pixmap,PixmapPtr dst_pixmap,int dx,int dy,int alu,RegionPtr src_reg,uint32_t plane_mask)907 vmwgfx_copy_prepare(struct saa_driver *driver,
908 		    PixmapPtr src_pixmap,
909 		    PixmapPtr dst_pixmap,
910 		    int dx,
911 		    int dy,
912 		    int alu,
913 		    RegionPtr src_reg,
914 		    uint32_t plane_mask)
915 {
916     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
917     struct vmwgfx_saa_pixmap *src_vpix;
918     struct vmwgfx_saa_pixmap *dst_vpix;
919     Bool has_dirty_hw;
920     Bool has_valid_hw;
921 
922     if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) ||
923 	alu != GXcopy || !vsaa->is_master)
924 	return FALSE;
925 
926     src_vpix = vmwgfx_saa_pixmap(src_pixmap);
927     dst_vpix = vmwgfx_saa_pixmap(dst_pixmap);
928 
929     vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg,
930 			     &has_dirty_hw, &has_valid_hw);
931 
932     if (vmwgfx_is_present_hw(dst_pixmap) &&
933 	src_vpix->backing & VMWGFX_PIX_SURFACE) {
934 
935 	if (!has_dirty_hw && !has_valid_hw)
936 	    return FALSE;
937 
938 	if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg))
939 	    return FALSE;
940 	if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) {
941 	    vsaa->present_copy = TRUE;
942 	    return TRUE;
943 	}
944 	return FALSE;
945     }
946 
947     vsaa->present_copy = FALSE;
948     if (src_vpix != dst_vpix) {
949 
950 	/*
951 	 * Use hardware acceleration either if source is partially only
952 	 * in hardware, or if source is entirely in hardware and destination
953 	 * has a hardware surface.
954 	 */
955 
956 	if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL)))
957 	    return FALSE;
958 
959 	/*
960 	 * Determine surface formats.
961 	 */
962 
963 	if (src_vpix->base.src_format == 0) {
964 	    if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
965 		return FALSE;
966 	} else {
967 	    if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB ||
968 		!vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format))
969 		return FALSE;
970 	}
971 
972 	if (dst_vpix->base.dst_format == 0) {
973 	    if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
974 		return FALSE;
975 	} else {
976 	    if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB ||
977 		!vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format))
978 		return FALSE;
979 	}
980 
981 	/*
982 	 * Create hardware surfaces.
983 	 */
984 
985 	if (!vmwgfx_hw_commit(src_pixmap))
986 	    return FALSE;
987 	if (!vmwgfx_hw_commit(dst_pixmap))
988 	    return FALSE;
989 
990 	/*
991 	 * Migrate data.
992 	 */
993 
994 	if (!vmwgfx_hw_validate(src_pixmap, src_reg)) {
995 	    xa_copy_done(vsaa->xa_ctx);
996 	    xa_context_flush(vsaa->xa_ctx);
997 	    return FALSE;
998 	}
999 
1000 	/*
1001 	 * Setup copy state.
1002 	 */
1003 
1004 	if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) !=
1005 	    XA_ERR_NONE)
1006 	    return FALSE;
1007 
1008 	return TRUE;
1009     }
1010 
1011     return FALSE;
1012 }
1013 
1014 
1015 static void
vmwgfx_present_done(struct vmwgfx_saa * vsaa)1016 vmwgfx_present_done(struct vmwgfx_saa *vsaa)
1017 {
1018     ScreenPtr pScreen = vsaa->pScreen;
1019     struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix;
1020 
1021     (void) pScreen;
1022     if (!vsaa->diff_valid)
1023 	return;
1024 
1025     (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id,
1026 			  vsaa->xdiff, vsaa->ydiff,
1027 			  &vsaa->present_region, vsaa->src_handle);
1028 
1029     REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff);
1030     REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage,
1031 		 &vsaa->present_region);
1032     vsaa->diff_valid = FALSE;
1033     REGION_UNINIT(pScreen, &vsaa->present_region);
1034 }
1035 
1036 static void
vmwgfx_present_copy(struct vmwgfx_saa * vsaa,int src_x,int src_y,int dst_x,int dst_y,int w,int h)1037 vmwgfx_present_copy(struct vmwgfx_saa *vsaa,
1038 		    int src_x,
1039 		    int src_y,
1040 		    int dst_x,
1041 		    int dst_y,
1042 		    int w,
1043 		    int h)
1044 {
1045     int xdiff = dst_x - src_x;
1046     int ydiff = dst_y - src_y;
1047     BoxRec box;
1048     RegionRec reg;
1049 
1050     if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff)))
1051 	(void) vmwgfx_present_done(vsaa);
1052 
1053     if (!vsaa->diff_valid) {
1054 	vsaa->xdiff = xdiff;
1055 	vsaa->ydiff = ydiff;
1056 	vsaa->diff_valid = TRUE;
1057     }
1058 
1059     box.x1 = src_x;
1060     box.x2 = src_x + w;
1061     box.y1 = src_y;
1062     box.y2 = src_y + h;
1063 
1064     REGION_INIT(pScreen, &reg, &box, 1);
1065     REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, &reg);
1066     REGION_UNINIT(pScreen, &reg);
1067 }
1068 
1069 static void
vmwgfx_copy(struct saa_driver * driver,int src_x,int src_y,int dst_x,int dst_y,int w,int h)1070 vmwgfx_copy(struct saa_driver *driver,
1071 	    int src_x,
1072 	    int src_y,
1073 	    int dst_x,
1074 	    int dst_y,
1075 	    int w,
1076 	    int h)
1077 {
1078     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1079 
1080     if (vsaa->present_copy) {
1081 	vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h);
1082 	return;
1083     }
1084     xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h);
1085 }
1086 
1087 static void
vmwgfx_copy_done(struct saa_driver * driver)1088 vmwgfx_copy_done(struct saa_driver *driver)
1089 {
1090     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1091 
1092     if (vsaa->present_copy) {
1093 	vmwgfx_present_done(vsaa);
1094 	return;
1095     }
1096     xa_copy_done(vsaa->xa_ctx);
1097     xa_context_flush(vsaa->xa_ctx);
1098 }
1099 
1100 static Bool
vmwgfx_composite_prepare(struct saa_driver * driver,CARD8 op,PicturePtr src_pict,PicturePtr mask_pict,PicturePtr dst_pict,PixmapPtr src_pix,PixmapPtr mask_pix,PixmapPtr dst_pix,RegionPtr src_region,RegionPtr mask_region,RegionPtr dst_region)1101 vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op,
1102 			 PicturePtr src_pict, PicturePtr mask_pict,
1103 			 PicturePtr dst_pict,
1104 			 PixmapPtr src_pix, PixmapPtr mask_pix,
1105 			 PixmapPtr dst_pix,
1106 			 RegionPtr src_region,
1107 			 RegionPtr mask_region,
1108 			 RegionPtr dst_region)
1109 {
1110     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1111     struct vmwgfx_saa_pixmap *src_vpix;
1112     struct vmwgfx_saa_pixmap *dst_vpix;
1113     struct vmwgfx_saa_pixmap *mask_vpix;
1114     Bool tmp_valid_hw;
1115     Bool dirty_hw;
1116     Bool valid_hw;
1117     RegionRec empty;
1118     struct xa_composite *xa_comp;
1119 
1120     if (!vsaa->is_master)
1121 	return FALSE;
1122 
1123     REGION_NULL(pScreen, &empty);
1124 
1125     /*
1126      * First we define our migration policy. We accelerate only if there
1127      * are dirty hw regions to be read or if all source data is
1128      * available in hw, and the destination has a hardware surface.
1129      */
1130     dst_vpix = vmwgfx_saa_pixmap(dst_pix);
1131     valid_hw = (dst_vpix->hw != NULL);
1132     if (saa_op_reads_destination(op)) {
1133 	vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region,
1134 				 &dirty_hw, &tmp_valid_hw);
1135 	valid_hw = (valid_hw && tmp_valid_hw);
1136     } else {
1137 	dirty_hw = FALSE;
1138 	dst_region = &empty;
1139     }
1140 
1141     if (src_pix && !dirty_hw) {
1142 	src_vpix = vmwgfx_saa_pixmap(src_pix);
1143 	vmwgfx_check_hw_contents(vsaa, src_vpix, src_region,
1144 				 &dirty_hw, &tmp_valid_hw);
1145 	valid_hw = (valid_hw && tmp_valid_hw);
1146     }
1147 
1148     if (mask_pict && mask_pix && !dirty_hw) {
1149 	mask_vpix = vmwgfx_saa_pixmap(mask_pix);
1150 	vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region,
1151 				 &dirty_hw, &tmp_valid_hw);
1152 	valid_hw = (valid_hw && tmp_valid_hw);
1153     }
1154 
1155     /*
1156      * In rendercheck mode we try to accelerate all supported
1157      * composite operations.
1158      */
1159 
1160     if (!valid_hw && !dirty_hw && !vsaa->rendercheck)
1161 	goto out_err;
1162 
1163     /*
1164      * Then, setup most of the XA composite state (except hardware surfaces)
1165      * and check whether XA can accelerate.
1166      */
1167 
1168     if (!mask_pix)
1169 	mask_pict = NULL;
1170     xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op,
1171 				   src_pict, mask_pict, dst_pict);
1172     if (!xa_comp)
1173 	goto out_err;
1174 
1175     if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE)
1176 	goto out_err;
1177 
1178     /*
1179      * Check that we can create the needed hardware surfaces.
1180      */
1181     if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format))
1182 	goto out_err;
1183     if (mask_pict && mask_pix &&
1184 	!vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format))
1185 	goto out_err;
1186     if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format))
1187 	goto out_err;
1188 
1189     /*
1190      * Seems OK. Commit the changes, creating hardware surfaces.
1191      */
1192     if (src_pix && !vmwgfx_hw_commit(src_pix))
1193 	goto out_err;
1194     if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix))
1195 	goto out_err;
1196     if (!vmwgfx_hw_commit(dst_pix))
1197 	goto out_err;
1198 
1199     /*
1200      * Update the XA state with our hardware surfaces and
1201      * surface formats
1202      */
1203     if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix))
1204 	goto out_err;
1205 
1206     /*
1207      * Migrate data to surfaces.
1208      */
1209     if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL))
1210 	goto out_err;
1211     if (mask_pict && mask_pix && mask_region &&
1212 	!vmwgfx_hw_validate(mask_pix, NULL))
1213 	goto out_err;
1214     if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL))
1215 	goto out_err;
1216 
1217 
1218     /*
1219      * Bind the XA state. This must be done after data migration, since
1220      * migration may change the hardware surfaces.
1221      */
1222     if (xa_composite_prepare(vsaa->xa_ctx, xa_comp))
1223 	goto out_err;
1224 
1225     return TRUE;
1226 
1227   out_err:
1228     return FALSE;
1229 }
1230 
1231 static void
vmwgfx_composite(struct saa_driver * driver,int src_x,int src_y,int mask_x,int mask_y,int dst_x,int dst_y,int width,int height)1232 vmwgfx_composite(struct saa_driver *driver,
1233 		 int src_x, int src_y, int mask_x, int mask_y,
1234 		 int dst_x, int dst_y,
1235 		 int width, int height)
1236 {
1237     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1238 
1239     xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y,
1240 		      dst_x, dst_y, width, height);
1241 }
1242 
1243 static void
vmwgfx_composite_done(struct saa_driver * driver)1244 vmwgfx_composite_done(struct saa_driver *driver)
1245 {
1246    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1247 
1248    xa_composite_done(vsaa->xa_ctx);
1249    xa_context_flush(vsaa->xa_ctx);
1250 }
1251 
1252 static void
vmwgfx_takedown(struct saa_driver * driver)1253 vmwgfx_takedown(struct saa_driver *driver)
1254 {
1255     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1256 
1257     if (vsaa->vcomp)
1258 	vmwgfx_free_composite(vsaa->vcomp);
1259     free(vsaa);
1260 }
1261 
1262 /*
1263  * This function call originates from the damage layer (outside SAA)
1264  * to indicate that an operation is complete, and that damage is being
1265  * processed.
1266  */
1267 static void
vmwgfx_operation_complete(struct saa_driver * driver,PixmapPtr pixmap)1268 vmwgfx_operation_complete(struct saa_driver *driver,
1269 			  PixmapPtr pixmap)
1270 {
1271     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1272     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
1273     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
1274     ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen);
1275 
1276     /*
1277      * Make dri2 drawables up to date, or add them to the flush list
1278      * executed at glxWaitX(). Currently glxWaitX() is broken, so
1279      * we flush immediately, unless we're VT-switched away, in which
1280      * case a flush would deadlock in the kernel.
1281      *
1282      * For pixmaps for which vpix->hw_is_hosted is true, we can explicitly
1283      * inform the compositor when contents has changed, so for those pixmaps
1284      * we defer the upload until the compositor is informed, by putting
1285      * them on the sync_x_list. Note that hw_is_dri2_fronts take precedence.
1286      */
1287     if (vpix->hw && (vpix->hw_is_dri2_fronts || vpix->hw_is_hosted)) {
1288 	if (pScrn->vtSema && vpix->hw_is_dri2_fronts &&
1289 	    vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) {
1290 
1291 	    REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
1292 	    return;
1293 	}
1294 
1295 	if (WSBMLISTEMPTY(&vpix->sync_x_head))
1296 	    WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list);
1297     }
1298 }
1299 
1300 /*
1301  * This function is called by SAA to indicate that SAA has
1302  * dirtied a region of a pixmap, either as hw (accelerated) or as
1303  * !hw (not accelerated).
1304  */
1305 static Bool
vmwgfx_dirty(struct saa_driver * driver,PixmapPtr pixmap,Bool hw,RegionPtr damage)1306 vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap,
1307 	     Bool hw, RegionPtr damage)
1308 {
1309     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
1310     struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
1311     struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
1312 
1313     /*
1314      * Return if this is not a scanout pixmap.
1315      */
1316     if (WSBMLISTEMPTY(&vpix->scanout_list))
1317 	return TRUE;
1318 
1319 #if 0
1320     /*
1321      * This code can be enabled to immediately upload scanout sw
1322      * contents to the hw surface. Otherwise this is done
1323      * just before we call the kms update function for the hw
1324      * surface.
1325      */
1326     if (vpix->scanout_hw) {
1327 	if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage))
1328 	    return FALSE;
1329 
1330 	REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow,
1331 			&spix->dirty_shadow, damage);
1332 	hw = TRUE;
1333     }
1334 #endif
1335 
1336     /*
1337      * Is the new scanout damage hw or sw?
1338      */
1339     if (hw) {
1340 	/*
1341 	 * Dump pending present into present tracking region.
1342 	 */
1343 	if (vpix->dirty_present &&
1344 	    REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) {
1345 	    REGION_UNION(vsaa->pScreen, vpix->dirty_present,
1346 			 vpix->dirty_present, damage);
1347 	    REGION_EMPTY(vsaa->pScreen, vpix->present_damage);
1348 	} else {
1349 	    if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) {
1350 		RegionRec reg;
1351 
1352 		REGION_NULL(vsaa->pScreen, &reg);
1353 		REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_update,
1354 				 damage);
1355 		if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
1356 		    vsaa->present_flush(vsaa->pScreen);
1357 		REGION_UNINIT(pScreen, &reg);
1358 	    }
1359 	    REGION_UNION(vsaa->pScreen, vpix->pending_present,
1360 			 vpix->pending_present, damage);
1361 	    if (vpix->dirty_present)
1362 		REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
1363 				vpix->dirty_present, damage);
1364 	}
1365     } else {
1366 	    if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) {
1367 		RegionRec reg;
1368 
1369 		REGION_NULL(vsaa->pScreen, &reg);
1370 		REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_present,
1371 				 damage);
1372 		if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
1373 		    vsaa->present_flush(vsaa->pScreen);
1374 		REGION_UNINIT(pScreen, &reg);
1375 	    }
1376 	    REGION_UNION(vsaa->pScreen, vpix->pending_update,
1377 			 vpix->pending_update, damage);
1378 	    if (vpix->dirty_present)
1379 		REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
1380 				vpix->dirty_present, damage);
1381     }
1382 
1383     return TRUE;
1384 }
1385 
1386 
1387 static const struct saa_driver vmwgfx_saa_driver = {
1388     .saa_major = SAA_VERSION_MAJOR,
1389     .saa_minor = SAA_VERSION_MINOR,
1390     .pixmap_size = sizeof(struct vmwgfx_saa_pixmap),
1391     .damage = vmwgfx_dirty,
1392     .operation_complete = vmwgfx_operation_complete,
1393     .download_from_hw = vmwgfx_download_from_hw,
1394     .release_from_cpu = vmwgfx_release_from_cpu,
1395     .sync_for_cpu = vmwgfx_sync_for_cpu,
1396     .map = vmwgfx_map,
1397     .unmap = vmwgfx_unmap,
1398     .create_pixmap = vmwgfx_create_pixmap,
1399     .destroy_pixmap = vmwgfx_destroy_pixmap,
1400     .modify_pixmap_header = vmwgfx_modify_pixmap_header,
1401     .copy_prepare = vmwgfx_copy_prepare,
1402     .copy = vmwgfx_copy,
1403     .copy_done = vmwgfx_copy_done,
1404     .composite_prepare = vmwgfx_composite_prepare,
1405     .composite = vmwgfx_composite,
1406     .composite_done = vmwgfx_composite_done,
1407     .takedown = vmwgfx_takedown,
1408 };
1409 
1410 
1411 Bool
vmwgfx_saa_init(ScreenPtr pScreen,int drm_fd,struct xa_tracker * xat,void (* present_flush)(ScreenPtr pScreen),Bool direct_presents,Bool only_hw_presents,Bool rendercheck,Bool has_screen_targets)1412 vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
1413 		void (*present_flush)(ScreenPtr pScreen),
1414 		Bool direct_presents,
1415 		Bool only_hw_presents,
1416 		Bool rendercheck,
1417 		Bool has_screen_targets)
1418 {
1419     struct vmwgfx_saa *vsaa;
1420 
1421     vsaa = calloc(1, sizeof(*vsaa));
1422     if (!vsaa)
1423 	return FALSE;
1424 
1425     if (xat == NULL) {
1426 	direct_presents = FALSE;
1427 	only_hw_presents = FALSE;
1428 	has_screen_targets = FALSE;
1429     }
1430 
1431     vsaa->pScreen = pScreen;
1432     vsaa->xat = xat;
1433     if (xat)
1434 	vsaa->xa_ctx = xa_context_default(xat);
1435     vsaa->drm_fd = drm_fd;
1436     vsaa->present_flush = present_flush;
1437     vsaa->can_optimize_dma = TRUE;
1438     vsaa->use_present_opt = direct_presents;
1439     vsaa->only_hw_presents = only_hw_presents;
1440     vsaa->rendercheck = rendercheck;
1441     vsaa->is_master = TRUE;
1442     vsaa->known_prime_format = FALSE;
1443     vsaa->has_screen_targets = has_screen_targets;
1444     WSBMINITLISTHEAD(&vsaa->sync_x_list);
1445     WSBMINITLISTHEAD(&vsaa->pixmaps);
1446 
1447     vsaa->driver = vmwgfx_saa_driver;
1448     vsaa->vcomp = vmwgfx_alloc_composite();
1449 
1450     if (!vsaa->vcomp)
1451 	vsaa->driver.composite_prepare = NULL;
1452 
1453     if (!saa_driver_init(pScreen, &vsaa->driver))
1454 	goto out_no_saa;
1455 
1456     return TRUE;
1457   out_no_saa:
1458     free(vsaa);
1459     return FALSE;
1460 }
1461 
1462 /*
1463  * *************************************************************************
1464  * Scanout functions.
1465  * These do not strictly belong here, but we choose to hide the scanout
1466  * pixmap private data in the saa pixmaps. Might want to revisit this.
1467  */
1468 
1469 /*
1470  * Make sure we flush / update this scanout on next update run.
1471  */
1472 
1473 void
vmwgfx_scanout_refresh(PixmapPtr pixmap)1474 vmwgfx_scanout_refresh(PixmapPtr pixmap)
1475 {
1476     ScreenPtr pScreen = pixmap->drawable.pScreen;
1477     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
1478     BoxRec box;
1479 
1480     (void) pScreen;
1481     box.x1 = 0;
1482     box.y1 = 0;
1483     box.x2 = pixmap->drawable.width;
1484     box.y2 = pixmap->drawable.height;
1485 
1486     REGION_RESET(vsaa->pScreen, vpix->pending_present, &box);
1487     if (vpix->dirty_present)
1488 	REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
1489 			vpix->pending_present, vpix->dirty_present);
1490     REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
1491 		    vpix->pending_present, &vpix->base.dirty_shadow);
1492     REGION_COPY(vsaa->pScreen, vpix->pending_update,
1493 		&vpix->base.dirty_shadow);
1494 }
1495 
1496 /*
1497  * Take a "scanout reference" on a pixmap. If this is the first scanout
1498  * reference, allocate resources needed for scanout, like proper
1499  * damage tracking and kms fbs.
1500  */
1501 
1502 uint32_t
vmwgfx_scanout_ref(struct vmwgfx_screen_entry * entry,Bool scanout_equals_pixmap)1503 vmwgfx_scanout_ref(struct vmwgfx_screen_entry  *entry,
1504 		   Bool scanout_equals_pixmap)
1505 {
1506     PixmapPtr pixmap = entry->pixmap;
1507     struct vmwgfx_saa *vsaa =
1508 	to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
1509     struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
1510 
1511     if (WSBMLISTEMPTY(&vpix->scanout_list)) {
1512 	uint32_t handle, dummy;
1513 	unsigned int depth;
1514 
1515 	vpix->scanout_hw = vsaa->only_hw_presents ||
1516 	    (vsaa->has_screen_targets && scanout_equals_pixmap);
1517 
1518 	if (vpix->scanout_hw) {
1519 	    /*
1520 	     * The KMS fb will be a HW surface. Create it, add damage
1521 	     * and get the handle.
1522 	     */
1523 	    if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT |
1524 					  XA_FLAG_RENDER_TARGET, 0, NULL))
1525 		goto out_err;
1526 	    if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0)
1527 		goto out_err;
1528 	    depth = xa_format_depth(xa_surface_format(vpix->hw));
1529 
1530 	} else {
1531 	    /*
1532 	     * The KMS fb will be a Guest Memory Region. Create it,
1533 	     * add damage and get the handle.
1534 	     */
1535 	    if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
1536 		goto out_err;
1537 
1538 	    handle = vpix->gmr->handle;
1539 	    depth = pixmap->drawable.depth;
1540 
1541 	}
1542 
1543         if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt))
1544 	    goto out_no_present;
1545 
1546 	if (drmModeAddFB(vsaa->drm_fd,
1547 			 pixmap->drawable.width,
1548 			 pixmap->drawable.height,
1549 			 depth,
1550 			 pixmap->drawable.bitsPerPixel,
1551 			 pixmap->devKind,
1552 			 handle,
1553 			 &vpix->fb_id) != 0)
1554 	    goto out_no_fb;;
1555     }
1556     pixmap->refcnt += 1;
1557     WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list);
1558     return vpix->fb_id;
1559 
1560   out_no_fb:
1561     vmwgfx_pixmap_remove_present(vpix);
1562   out_no_present:
1563     vmwgfx_pixmap_remove_damage(pixmap);
1564   out_err:
1565     vpix->fb_id = -1;
1566     return -1;
1567 }
1568 
1569 /*
1570  * Free a "scanout reference" on a pixmap. If this was the last scanout
1571  * reference, free pixmap resources needed for scanout, like
1572  * damage tracking and kms fbs.
1573  */
1574 void
vmwgfx_scanout_unref(struct vmwgfx_screen_entry * entry)1575 vmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry)
1576 {
1577     struct vmwgfx_saa *vsaa;
1578     struct vmwgfx_saa_pixmap *vpix;
1579     PixmapPtr pixmap = entry->pixmap;
1580 
1581     if (!pixmap)
1582 	return;
1583 
1584     vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
1585     vpix = vmwgfx_saa_pixmap(pixmap);
1586     WSBMLISTDELINIT(&entry->scanout_head);
1587 
1588     if (WSBMLISTEMPTY(&vpix->scanout_list)) {
1589 	REGION_EMPTY(vsaa->pScreen, vpix->pending_update);
1590 	drmModeRmFB(vsaa->drm_fd, vpix->fb_id);
1591 	vpix->fb_id = -1;
1592 	vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL);
1593 	vmwgfx_pixmap_remove_present(vpix);
1594 	vmwgfx_pixmap_remove_damage(pixmap);
1595     }
1596 
1597     entry->pixmap = NULL;
1598     pixmap->drawable.pScreen->DestroyPixmap(pixmap);
1599 }
1600 
1601 void
vmwgfx_saa_set_master(ScreenPtr pScreen)1602 vmwgfx_saa_set_master(ScreenPtr pScreen)
1603 {
1604     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
1605 
1606     vsaa->is_master = TRUE;
1607     vmwgfx_flush_dri2(pScreen);
1608 }
1609 
1610 void
vmwgfx_saa_drop_master(ScreenPtr pScreen)1611 vmwgfx_saa_drop_master(ScreenPtr pScreen)
1612 {
1613     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
1614     struct _WsbmListHead *list;
1615     struct vmwgfx_saa_pixmap *vpix;
1616     struct saa_pixmap *spix;
1617 
1618     WSBMLISTFOREACH(list, &vsaa->pixmaps) {
1619 	vpix = WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, pixmap_list);
1620 	spix = &vpix->base;
1621 
1622 	if (!vpix->hw)
1623 	    continue;
1624 
1625 	(void) vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
1626 				       &spix->dirty_hw);
1627 	REGION_EMPTY(draw->pScreen, &spix->dirty_hw);
1628     }
1629 
1630     vsaa->is_master = FALSE;
1631 }
1632 
1633 /*
1634  * *************************************************************************
1635  * Helpers for hosted.
1636  */
1637 
1638 #if (XA_TRACKER_VERSION_MAJOR >= 2) && defined(HAVE_LIBDRM_2_4_38)
1639 
1640 /**
1641  * vmwgfx_saa_copy_to_surface - Copy Drawable contents to an external surface.
1642  *
1643  * @pDraw: Pointer to source drawable.
1644  * @surface_fd: Prime file descriptor of external surface to copy to.
1645  * @dst_box: BoxRec describing the destination bounding box.
1646  * @region: Region of drawable to copy. Note: The code assumes that the
1647  * region is relative to the drawable origin, not the underlying pixmap
1648  * origin.
1649  *
1650  * Copies the contents (both software- and accelerated contents) to an
1651  * external surface.
1652  */
1653 Bool
vmwgfx_saa_copy_to_surface(DrawablePtr pDraw,uint32_t surface_fd,const BoxRec * dst_box,RegionPtr region)1654 vmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd,
1655 			   const BoxRec *dst_box, RegionPtr region)
1656 {
1657     ScreenPtr pScreen = pDraw->pScreen;
1658     struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
1659     PixmapPtr src;
1660     struct saa_pixmap *spix;
1661     struct vmwgfx_saa_pixmap *vpix;
1662     const BoxRec *box;
1663     int n;
1664     int sx, sy, dx, dy;
1665     struct xa_surface *dst;
1666     uint32_t handle;
1667     Bool ret = TRUE;
1668     RegionRec intersection;
1669     RegionPtr copy_region = region;
1670 
1671     if (vmwgfx_prime_fd_to_handle(vsaa->drm_fd, surface_fd, &handle) < 0)
1672 	return FALSE;
1673 
1674     dst = xa_surface_from_handle(vsaa->xat, pDraw->width, pDraw->height,
1675 				 pDraw->depth, xa_type_argb,
1676 				 xa_format_unknown,
1677 				 XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
1678 				 handle,
1679 				 (pDraw->width * pDraw->bitsPerPixel + 7) / 8);
1680 
1681     if (!dst) {
1682 	ret = FALSE;
1683 	goto out_no_surface;
1684     }
1685 
1686     /*
1687      * Assume damage region is relative to the source window.
1688      */
1689     src = saa_get_pixmap(pDraw, &sx, &sy);
1690     sx += pDraw->x;
1691     sy += pDraw->y;
1692     if (sx || sy)
1693 	REGION_TRANSLATE(pScreen, region, sx, sy);
1694 
1695     dx = dst_box->x1 - sx;
1696     dy = dst_box->y1 - sy;
1697 
1698     spix = saa_get_saa_pixmap(src);
1699     vpix = to_vmwgfx_saa_pixmap(spix);
1700 
1701     /*
1702      * Make sure software contents of the source pixmap is henceforth put
1703      * in a GMR to avoid the extra copy in the xa DMA.
1704      */
1705     vmwgfx_prefer_gmr(vsaa, src);
1706 
1707     /*
1708      * Determine the intersection between software contents and region to copy.
1709      */
1710 
1711     if (vsaa->known_prime_format) {
1712 	REGION_NULL(pScreen, &intersection);
1713 	if (!vpix->hw)
1714 	    REGION_COPY(pScreen, &intersection, region);
1715 	else if (spix->damage && REGION_NOTEMPTY(pScreen, &spix->dirty_shadow))
1716 	    REGION_INTERSECT(pScreen, &intersection, region, &spix->dirty_shadow);
1717 
1718 	/*
1719 	 * DMA software contents directly into the destination. Then subtract
1720 	 * the region we've DMA'd from the region to copy.
1721 	 */
1722 	if (REGION_NOTEMPTY(pScreen, &intersection)) {
1723 	    if (vmwgfx_saa_dma(vsaa, src, &intersection, TRUE, dx, dy, dst)) {
1724 		REGION_SUBTRACT(pScreen, &intersection, region, &intersection);
1725 		copy_region = &intersection;
1726 	    }
1727 	}
1728     }
1729 
1730     if (!REGION_NOTEMPTY(pScreen, copy_region))
1731 	goto out_no_copy;
1732 
1733     /*
1734      * Copy Hardware contents to the destination
1735      */
1736     box = REGION_RECTS(copy_region);
1737     n = REGION_NUM_RECTS(copy_region);
1738 
1739     if (!vmwgfx_hw_accel_validate(src, 0, 0, 0, copy_region)) {
1740 	ret = FALSE;
1741 	goto out_no_copy;
1742     }
1743 
1744     if (xa_copy_prepare(vsaa->xa_ctx, dst, vpix->hw) != XA_ERR_NONE) {
1745 	ret = FALSE;
1746 	goto out_no_copy;
1747     }
1748 
1749     while(n--) {
1750 	xa_copy(vsaa->xa_ctx, box->x1 + dx, box->y1 + dy, box->x1, box->y1,
1751 		box->x2 - box->x1, box->y2 - box->y1);
1752 	box++;
1753     }
1754 
1755     xa_copy_done(vsaa->xa_ctx);
1756     xa_context_flush(vsaa->xa_ctx);
1757 
1758   out_no_copy:
1759     if (vsaa->known_prime_format)
1760 	REGION_UNINIT(pScreen, &intersection);
1761     if (sx || sy)
1762 	REGION_TRANSLATE(pScreen, region, -sx, -sy);
1763     xa_surface_unref(dst);
1764   out_no_surface:
1765     vmwgfx_prime_release_handle(vsaa->drm_fd, handle);
1766 
1767     return ret;
1768 }
1769 #endif
1770