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, ®, &box, 1);
1065 REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®);
1066 REGION_UNINIT(pScreen, ®);
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 = ∅
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, ®);
1353 REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update,
1354 damage);
1355 if (REGION_NOTEMPTY(vsaa->pScreen, ®))
1356 vsaa->present_flush(vsaa->pScreen);
1357 REGION_UNINIT(pScreen, ®);
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, ®);
1370 REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present,
1371 damage);
1372 if (REGION_NOTEMPTY(vsaa->pScreen, ®))
1373 vsaa->present_flush(vsaa->pScreen);
1374 REGION_UNINIT(pScreen, ®);
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