mirror of
https://github.com/X11Libre/xf86-video-vmware.git
synced 2026-03-24 01:24:37 +00:00
Use server's new lifecycle API. That's an important step in order to decouple ourselves from the old, fragile proc wrapping. Without it, the driver might not work on newer Xservers anymore. For old Xservers adding a fallback. Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
1766 lines
45 KiB
C
1766 lines
45 KiB
C
/*
|
|
* Copyright 2011 VMWare, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
* of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Author: Thomas Hellstrom <thellstrom@vmware.com>
|
|
*/
|
|
|
|
#include <xorg-server.h>
|
|
#include <xorgVersion.h>
|
|
#include <mi.h>
|
|
#include <fb.h>
|
|
#include <xa_context.h>
|
|
#include "vmwgfx_saa.h"
|
|
#include "vmwgfx_drmi.h"
|
|
#include "vmwgfx_saa_priv.h"
|
|
#include <xf86drmMode.h>
|
|
|
|
/*
|
|
* Damage to be added as soon as we attach storage to the pixmap.
|
|
*/
|
|
static Bool
|
|
vmwgfx_pixmap_add_damage(PixmapPtr pixmap)
|
|
{
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
DrawablePtr draw = &pixmap->drawable;
|
|
BoxRec box;
|
|
|
|
if (spix->damage)
|
|
return TRUE;
|
|
|
|
if (!saa_add_damage(pixmap))
|
|
return FALSE;
|
|
|
|
box.x1 = 0;
|
|
box.x2 = draw->width;
|
|
box.y1 = 0;
|
|
box.y2 = draw->height;
|
|
|
|
if (vpix->hw) {
|
|
REGION_RESET(draw->pScreen, &spix->dirty_hw, &box);
|
|
REGION_EMPTY(draw->pScreen, &spix->dirty_shadow);
|
|
} else {
|
|
REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box);
|
|
REGION_EMPTY(draw->pScreen, &spix->dirty_hw);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
vmwgfx_pixmap_remove_damage(PixmapPtr pixmap)
|
|
{
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
|
|
if (!spix->damage || vpix->hw || vpix->gmr || vpix->malloc)
|
|
return;
|
|
|
|
DamageUnregister(spix->damage);
|
|
|
|
DamageDestroy(spix->damage);
|
|
spix->damage = NULL;
|
|
}
|
|
|
|
static void
|
|
vmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix)
|
|
{
|
|
if (vpix->dirty_present)
|
|
REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present);
|
|
if (vpix->present_damage)
|
|
REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage);
|
|
if (vpix->pending_update)
|
|
REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update);
|
|
if (vpix->pending_present)
|
|
REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present);
|
|
vpix->dirty_present = NULL;
|
|
vpix->present_damage = NULL;
|
|
vpix->pending_update = NULL;
|
|
vpix->pending_present = NULL;
|
|
}
|
|
|
|
static Bool
|
|
vmwgfx_pixmap_add_present(PixmapPtr pixmap, Bool present_opt)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
ScreenPtr pScreen = pixmap->drawable.pScreen;
|
|
(void) pScreen;
|
|
|
|
if (present_opt) {
|
|
vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0);
|
|
if (!vpix->dirty_present)
|
|
return FALSE;
|
|
vpix->present_damage = REGION_CREATE(pScreen, NULL, 0);
|
|
if (!vpix->present_damage)
|
|
goto out_no_present_damage;
|
|
}
|
|
vpix->pending_update = REGION_CREATE(pScreen, NULL, 0);
|
|
if (!vpix->pending_update)
|
|
goto out_no_pending_update;
|
|
vpix->pending_present = REGION_CREATE(pScreen, NULL, 0);
|
|
if (!vpix->pending_present)
|
|
goto out_no_pending_present;
|
|
|
|
return TRUE;
|
|
out_no_pending_present:
|
|
REGION_DESTROY(pScreen, vpix->pending_update);
|
|
out_no_pending_update:
|
|
if (vpix->present_damage)
|
|
REGION_DESTROY(pScreen, vpix->present_damage);
|
|
out_no_present_damage:
|
|
if (vpix->dirty_present)
|
|
REGION_DESTROY(pScreen, vpix->dirty_present);
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
vmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix)
|
|
{
|
|
if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) {
|
|
free(vpix->malloc);
|
|
vpix->malloc = NULL;
|
|
}
|
|
if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) {
|
|
xa_surface_destroy(vpix->hw);
|
|
vpix->hw = NULL;
|
|
}
|
|
if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) {
|
|
vmwgfx_dmabuf_destroy(vpix->gmr);
|
|
vpix->gmr = NULL;
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
vmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
size_t size;
|
|
struct vmwgfx_dmabuf *gmr;
|
|
void *addr;
|
|
|
|
if (vpix->gmr)
|
|
return TRUE;
|
|
|
|
size = pixmap->devKind * pixmap->drawable.height;
|
|
gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
|
|
if (!gmr)
|
|
return FALSE;
|
|
|
|
if (vpix->malloc) {
|
|
|
|
addr = vmwgfx_dmabuf_map(gmr);
|
|
if (!addr)
|
|
goto out_no_transfer;
|
|
memcpy(addr, vpix->malloc, size);
|
|
vmwgfx_dmabuf_unmap(gmr);
|
|
|
|
} else if (!vmwgfx_pixmap_add_damage(pixmap))
|
|
goto out_no_transfer;
|
|
|
|
vpix->backing |= VMWGFX_PIX_GMR;
|
|
vpix->backing &= ~VMWGFX_PIX_MALLOC;
|
|
vpix->gmr = gmr;
|
|
|
|
vmwgfx_pixmap_free_storage(vpix);
|
|
|
|
return TRUE;
|
|
|
|
out_no_transfer:
|
|
vmwgfx_dmabuf_destroy(gmr);
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
vmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
|
|
if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR)))
|
|
return FALSE;
|
|
|
|
if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) {
|
|
vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height);
|
|
if (!vpix->malloc)
|
|
goto out_no_malloc;
|
|
if (!vmwgfx_pixmap_add_damage(pixmap))
|
|
goto out_no_damage;
|
|
} else if (vpix->backing & VMWGFX_PIX_GMR)
|
|
return vmwgfx_pixmap_create_gmr(vsaa, pixmap);
|
|
|
|
return TRUE;
|
|
|
|
out_no_damage:
|
|
free(vpix->malloc);
|
|
vpix->malloc = NULL;
|
|
out_no_malloc:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* Makes sure all presented contents covered by @region are read
|
|
* back and are present in a valid GMR.
|
|
*/
|
|
|
|
static Bool
|
|
vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa,
|
|
PixmapPtr pixmap,
|
|
RegionPtr region)
|
|
{
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
RegionRec intersection;
|
|
|
|
if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) ||
|
|
!vpix->dirty_present)
|
|
return TRUE;
|
|
|
|
/*
|
|
* Intersect dirty region with region to be read back, if any.
|
|
*/
|
|
|
|
REGION_NULL(vsaa->pScreen, &intersection);
|
|
REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw);
|
|
REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection,
|
|
vpix->dirty_present);
|
|
|
|
if (region)
|
|
REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region);
|
|
|
|
if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection))
|
|
goto out;
|
|
|
|
/*
|
|
* Make really sure there is a GMR to read back to.
|
|
*/
|
|
|
|
if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
|
|
goto out_err;
|
|
|
|
if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id,
|
|
&intersection) != 0)
|
|
goto out_err;
|
|
|
|
REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw,
|
|
&spix->dirty_hw, &intersection);
|
|
out:
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
return TRUE;
|
|
|
|
out_err:
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
vmwgfx_saa_dma(struct vmwgfx_saa *vsaa,
|
|
PixmapPtr pixmap,
|
|
RegionPtr reg,
|
|
Bool to_hw,
|
|
int dx,
|
|
int dy,
|
|
struct xa_surface *srf)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
|
|
if (!srf)
|
|
srf = vpix->hw;
|
|
|
|
if (!srf || (!vpix->gmr && !vpix->malloc))
|
|
return TRUE;
|
|
|
|
if (vpix->gmr && vsaa->can_optimize_dma) {
|
|
uint32_t handle, dummy;
|
|
|
|
if (_xa_surface_handle(srf, &handle, &dummy) != 0)
|
|
goto out_err;
|
|
if (vmwgfx_dma(dx, dy, reg, vpix->gmr, pixmap->devKind, handle,
|
|
to_hw) != 0)
|
|
goto out_err;
|
|
} else {
|
|
uint8_t *data = (uint8_t *) vpix->malloc;
|
|
int ret;
|
|
|
|
if (vpix->gmr) {
|
|
data = (uint8_t *) vmwgfx_dmabuf_map(vpix->gmr);
|
|
if (!data)
|
|
goto out_err;
|
|
}
|
|
|
|
if (dx || dy) {
|
|
REGION_TRANSLATE(pScreen, reg, dx, dy);
|
|
data -= ((dx * pixmap->drawable.bitsPerPixel + 7)/8 +
|
|
dy * pixmap->devKind);
|
|
}
|
|
|
|
ret = xa_surface_dma(vsaa->xa_ctx, srf, data, pixmap->devKind,
|
|
(int) to_hw,
|
|
(struct xa_box *) REGION_RECTS(reg),
|
|
REGION_NUM_RECTS(reg));
|
|
if (to_hw)
|
|
xa_context_flush(vsaa->xa_ctx);
|
|
if (vpix->gmr)
|
|
vmwgfx_dmabuf_unmap(vpix->gmr);
|
|
if (dx || dy)
|
|
REGION_TRANSLATE(pScreen, reg, -dx, -dy);
|
|
if (ret)
|
|
goto out_err;
|
|
}
|
|
return TRUE;
|
|
out_err:
|
|
LogMessage(X_ERROR, "DMA %s surface failed.\n",
|
|
to_hw ? "to" : "from");
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static Bool
|
|
vmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap,
|
|
RegionPtr readback)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
|
|
RegionRec intersection;
|
|
|
|
if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback))
|
|
return FALSE;
|
|
|
|
if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw))
|
|
return TRUE;
|
|
|
|
if (!vpix->hw)
|
|
return TRUE;
|
|
|
|
REGION_NULL(vsaa->pScreen, &intersection);
|
|
REGION_INTERSECT(vsaa->pScreen, &intersection, readback,
|
|
&spix->dirty_hw);
|
|
readback = &intersection;
|
|
|
|
if (!vmwgfx_pixmap_create_sw(vsaa, pixmap))
|
|
goto out_err;
|
|
|
|
if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE, 0, 0, NULL))
|
|
goto out_err;
|
|
REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback);
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
|
|
return TRUE;
|
|
out_err:
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static Bool
|
|
vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap,
|
|
RegionPtr upload)
|
|
{
|
|
return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE,
|
|
0, 0, NULL);
|
|
}
|
|
|
|
static void
|
|
vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
|
|
{
|
|
// LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n",
|
|
// (unsigned long) pixmap, (unsigned) access);
|
|
}
|
|
|
|
static void *
|
|
vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
|
|
{
|
|
/*
|
|
* Errors in this functions will turn up in subsequent map
|
|
* calls.
|
|
*/
|
|
|
|
(void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *
|
|
vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
|
|
if (vpix->malloc)
|
|
return vpix->malloc;
|
|
else if (vpix->gmr)
|
|
return vmwgfx_dmabuf_map(vpix->gmr);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
|
|
if (vpix->gmr)
|
|
return vmwgfx_dmabuf_unmap(vpix->gmr);
|
|
|
|
// LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n",
|
|
// (unsigned long) pixmap, (unsigned) access);
|
|
;
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
|
|
*new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
|
|
|
|
WSBMINITLISTHEAD(&vpix->sync_x_head);
|
|
WSBMINITLISTHEAD(&vpix->scanout_list);
|
|
WSBMINITLISTHEAD(&vpix->pixmap_list);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
vmwgfx_hw_kill(struct vmwgfx_saa *vsaa,
|
|
struct saa_pixmap *spix)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
|
|
if (!vpix->hw)
|
|
return TRUE;
|
|
|
|
/*
|
|
* Read back any dirty regions from hardware.
|
|
*/
|
|
|
|
if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
|
|
&spix->dirty_hw))
|
|
return FALSE;
|
|
|
|
xa_surface_destroy(vpix->hw);
|
|
vpix->hw = NULL;
|
|
|
|
/*
|
|
* Remove damage tracking if this is not a scanout pixmap.
|
|
*/
|
|
|
|
if (WSBMLISTEMPTY(&vpix->scanout_list))
|
|
vmwgfx_pixmap_remove_damage(spix->pixmap);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
vmwgfx_flush_dri2(ScreenPtr pScreen)
|
|
{
|
|
struct vmwgfx_saa *vsaa =
|
|
to_vmwgfx_saa(saa_get_driver(pScreen));
|
|
struct _WsbmListHead *list, *next;
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
|
|
if (!pScrn->vtSema)
|
|
return;
|
|
|
|
WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) {
|
|
struct vmwgfx_saa_pixmap *vpix =
|
|
WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head);
|
|
struct saa_pixmap *spix = &vpix->base;
|
|
PixmapPtr pixmap = spix->pixmap;
|
|
|
|
if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) {
|
|
REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
|
|
WSBMLISTDELINIT(list);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap)
|
|
{
|
|
ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen;
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
(void) pScreen;
|
|
|
|
vpix->backing = 0;
|
|
vmwgfx_pixmap_free_storage(vpix);
|
|
|
|
/*
|
|
* Any damage we've registered has already been removed by the server
|
|
* at this point. Any attempt to unregister / destroy it will result
|
|
* in a double free.
|
|
*/
|
|
|
|
vmwgfx_pixmap_remove_present(vpix);
|
|
WSBMLISTDELINIT(&vpix->pixmap_list);
|
|
WSBMLISTDELINIT(&vpix->sync_x_head);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* Makes sure we have a surface with valid contents.
|
|
*/
|
|
|
|
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)
|
|
{
|
|
unsigned int i;
|
|
unsigned int height = (dst_height < src_height) ? dst_height : src_height;
|
|
unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch;
|
|
|
|
for(i=0; i<height; ++i) {
|
|
memcpy(dst, src, pitch);
|
|
dst += dst_pitch;
|
|
src += src_pitch;
|
|
}
|
|
}
|
|
|
|
|
|
static Bool
|
|
vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch,
|
|
unsigned int old_height, unsigned int old_width)
|
|
{
|
|
ScreenPtr pScreen = pixmap->drawable.pScreen;
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
DrawablePtr draw = &pixmap->drawable;
|
|
unsigned int size = pixmap->devKind * draw->height;
|
|
BoxRec b_box;
|
|
RegionRec b_reg;
|
|
|
|
/*
|
|
* Ignore copying errors. At worst they will show up as rendering
|
|
* artefacts.
|
|
*/
|
|
|
|
if (vpix->malloc) {
|
|
|
|
void *new_malloc = malloc(size);
|
|
if (!new_malloc)
|
|
return FALSE;
|
|
|
|
vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind,
|
|
old_pitch, draw->height,
|
|
old_height);
|
|
free(vpix->malloc);
|
|
vpix->malloc = new_malloc;
|
|
}
|
|
|
|
if (vpix->gmr) {
|
|
struct vmwgfx_dmabuf *gmr;
|
|
void *new_addr;
|
|
void *old_addr;
|
|
|
|
gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
|
|
if (!gmr)
|
|
return FALSE;
|
|
|
|
new_addr = vmwgfx_dmabuf_map(gmr);
|
|
old_addr = vmwgfx_dmabuf_map(vpix->gmr);
|
|
|
|
if (new_addr && old_addr)
|
|
vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind,
|
|
old_pitch, draw->height,
|
|
old_height);
|
|
else
|
|
LogMessage(X_ERROR, "Failed pixmap resize copy.\n");
|
|
|
|
if (old_addr)
|
|
vmwgfx_dmabuf_unmap(vpix->gmr);
|
|
if (new_addr)
|
|
vmwgfx_dmabuf_unmap(gmr);
|
|
vmwgfx_dmabuf_destroy(vpix->gmr);
|
|
vpix->gmr = gmr;
|
|
}
|
|
|
|
if (vpix->hw) {
|
|
if (!vmwgfx_xa_surface_redefine(vpix, vpix->hw, draw->width,
|
|
draw->height, draw->depth, xa_type_argb,
|
|
xa_format_unknown, vpix->xa_flags, 1))
|
|
return FALSE;
|
|
}
|
|
|
|
b_box.x1 = 0;
|
|
b_box.x2 = draw->width;
|
|
b_box.y1 = 0;
|
|
b_box.y2 = draw->height;
|
|
|
|
REGION_INIT(pScreen, &b_reg, &b_box, 1);
|
|
REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow,
|
|
&b_reg);
|
|
REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg);
|
|
if (vpix->dirty_present)
|
|
REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present,
|
|
&b_reg);
|
|
if (vpix->pending_update)
|
|
REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update,
|
|
&b_reg);
|
|
if (vpix->pending_present)
|
|
REGION_INTERSECT(pScreen, vpix->pending_present,
|
|
vpix->pending_present, &b_reg);
|
|
if (vpix->present_damage)
|
|
REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage,
|
|
&b_reg);
|
|
|
|
REGION_UNINIT(pScreen, &b_reg);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static Bool
|
|
vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth,
|
|
int bpp, int devkind, void *pixdata)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
ScreenPtr pScreen = pixmap->drawable.pScreen;
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
|
|
unsigned int old_height;
|
|
unsigned int old_width;
|
|
unsigned int old_pitch;
|
|
|
|
if (!vpix) {
|
|
LogMessage(X_ERROR, "Not an SAA pixmap.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (pixdata) {
|
|
vpix->backing = 0;
|
|
vmwgfx_pixmap_free_storage(vpix);
|
|
return FALSE;
|
|
}
|
|
|
|
if (depth <= 0)
|
|
depth = pixmap->drawable.depth;
|
|
|
|
if (bpp <= 0)
|
|
bpp = pixmap->drawable.bitsPerPixel;
|
|
|
|
if (w <= 0)
|
|
w = pixmap->drawable.width;
|
|
|
|
if (h <= 0)
|
|
h = pixmap->drawable.height;
|
|
|
|
if (w <= 0 || h <= 0 || depth <= 0)
|
|
return FALSE;
|
|
|
|
old_height = pixmap->drawable.height;
|
|
old_width = pixmap->drawable.width;
|
|
old_pitch = pixmap->devKind;
|
|
|
|
if (!miModifyPixmapHeader(pixmap, w, h, depth,
|
|
bpp, devkind, NULL))
|
|
goto out_no_modify;
|
|
|
|
if (!vpix->backing)
|
|
vpix->backing = VMWGFX_PIX_MALLOC;
|
|
|
|
vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width);
|
|
vmwgfx_pixmap_free_storage(vpix);
|
|
if (WSBMLISTEMPTY(&vpix->pixmap_list))
|
|
WSBMLISTADDTAIL(&vpix->pixmap_list, &vsaa->pixmaps);
|
|
|
|
return TRUE;
|
|
|
|
out_no_modify:
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
vmwgfx_present_prepare(struct vmwgfx_saa *vsaa,
|
|
struct vmwgfx_saa_pixmap *src_vpix,
|
|
struct vmwgfx_saa_pixmap *dst_vpix)
|
|
{
|
|
ScreenPtr pScreen = vsaa->pScreen;
|
|
unsigned int dummy;
|
|
|
|
(void) pScreen;
|
|
if (src_vpix == dst_vpix || !src_vpix->hw ||
|
|
_xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0)
|
|
return FALSE;
|
|
|
|
REGION_NULL(pScreen, &vsaa->present_region);
|
|
vsaa->diff_valid = FALSE;
|
|
vsaa->dst_vpix = dst_vpix;
|
|
vsaa->present_flush(pScreen);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Determine whether we should try present copies on this pixmap.
|
|
*/
|
|
|
|
static Bool
|
|
vmwgfx_is_present_hw(PixmapPtr pixmap)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
return (vpix->dirty_present != NULL);
|
|
}
|
|
|
|
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)
|
|
{
|
|
RegionRec intersection;
|
|
|
|
|
|
if (!vpix->hw) {
|
|
*has_dirty_hw = FALSE;
|
|
*has_valid_hw = FALSE;
|
|
return;
|
|
}
|
|
|
|
if (!region) {
|
|
*has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen,
|
|
&vpix->base.dirty_hw);
|
|
*has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen,
|
|
&vpix->base.dirty_shadow);
|
|
return;
|
|
}
|
|
|
|
REGION_NULL(vsaa->pScreen, &intersection);
|
|
REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw,
|
|
region);
|
|
*has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection);
|
|
REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow,
|
|
region);
|
|
*has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection);
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
}
|
|
|
|
/**
|
|
* vmwgfx_prefer_gmr: Prefer a dma buffer over malloced memory for software
|
|
* rendered storage
|
|
*
|
|
* @vsaa: Pointer to a struct vmwgfx_saa accelerator.
|
|
* @pixmap: Pointer to pixmap whose storage preference we want to alter.
|
|
*
|
|
* If possible, alter the storage or future storage of the software contents
|
|
* of this pixmap to be in a DMA buffer rather than in malloced memory.
|
|
* This function should be called when it's likely that frequent DMA operations
|
|
* will occur between a surface and the memory holding the software
|
|
* contents.
|
|
*/
|
|
static void
|
|
vmwgfx_prefer_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
|
|
if (vsaa->can_optimize_dma) {
|
|
if (vpix->malloc) {
|
|
(void) vmwgfx_pixmap_create_gmr(vsaa, pixmap);
|
|
} else if (vpix->backing & VMWGFX_PIX_MALLOC) {
|
|
vpix->backing |= VMWGFX_PIX_GMR;
|
|
vpix->backing &= ~VMWGFX_PIX_MALLOC;
|
|
}
|
|
}
|
|
}
|
|
|
|
Bool
|
|
vmwgfx_create_hw(struct vmwgfx_saa *vsaa,
|
|
PixmapPtr pixmap,
|
|
Bool shared)
|
|
{
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
struct xa_surface *hw;
|
|
uint32_t new_flags;
|
|
|
|
if (!vsaa->xat)
|
|
return FALSE;
|
|
|
|
if (!shared) {
|
|
if (vpix->hw)
|
|
return TRUE;
|
|
|
|
new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) |
|
|
vpix->staging_add_flags | XA_FLAG_SHARED;
|
|
|
|
hw = xa_surface_create(vsaa->xat,
|
|
pixmap->drawable.width,
|
|
pixmap->drawable.height,
|
|
0,
|
|
xa_type_other,
|
|
vpix->staging_format,
|
|
new_flags);
|
|
} else {
|
|
new_flags = vpix->xa_flags;
|
|
hw = vpix->hw;
|
|
}
|
|
|
|
if (hw == NULL)
|
|
return FALSE;
|
|
|
|
vpix->xa_flags = new_flags;
|
|
vpix->hw = hw;
|
|
|
|
if (!vmwgfx_pixmap_add_damage(pixmap))
|
|
goto out_no_damage;
|
|
|
|
vpix->backing |= VMWGFX_PIX_SURFACE;
|
|
vmwgfx_pixmap_free_storage(vpix);
|
|
|
|
/*
|
|
* If there is a HW surface, make sure that the shadow is
|
|
* (or will be) a GMR, provided we can do fast DMAs from / to it.
|
|
*/
|
|
vmwgfx_prefer_gmr(vsaa, pixmap);
|
|
|
|
return TRUE;
|
|
|
|
out_no_damage:
|
|
vpix->hw = NULL;
|
|
xa_surface_destroy(hw);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
Bool
|
|
vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region)
|
|
{
|
|
struct vmwgfx_saa *vsaa =
|
|
to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
RegionRec intersection;
|
|
|
|
if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region))
|
|
return FALSE;
|
|
|
|
REGION_NULL(vsaa->pScreen, &intersection);
|
|
REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow);
|
|
|
|
if (vpix->dirty_present)
|
|
REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present,
|
|
&spix->dirty_shadow);
|
|
|
|
if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) {
|
|
RegionPtr upload = &intersection;
|
|
|
|
/*
|
|
* Check whether we need to upload from GMR.
|
|
*/
|
|
|
|
if (region) {
|
|
REGION_INTERSECT(vsaa->pScreen, &intersection, region,
|
|
&intersection);
|
|
upload = &intersection;
|
|
}
|
|
|
|
if (REGION_NOTEMPTY(vsaa->pScreen, upload)) {
|
|
Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload);
|
|
if (ret) {
|
|
REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow,
|
|
&spix->dirty_shadow, upload);
|
|
if (vpix->dirty_present)
|
|
REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
|
|
vpix->dirty_present, upload);
|
|
} else {
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
REGION_UNINIT(vsaa->pScreen, &intersection);
|
|
return TRUE;
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
struct vmwgfx_saa_pixmap *src_vpix;
|
|
struct vmwgfx_saa_pixmap *dst_vpix;
|
|
Bool has_dirty_hw;
|
|
Bool has_valid_hw;
|
|
|
|
if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) ||
|
|
alu != GXcopy || !vsaa->is_master)
|
|
return FALSE;
|
|
|
|
src_vpix = vmwgfx_saa_pixmap(src_pixmap);
|
|
dst_vpix = vmwgfx_saa_pixmap(dst_pixmap);
|
|
|
|
vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg,
|
|
&has_dirty_hw, &has_valid_hw);
|
|
|
|
if (vmwgfx_is_present_hw(dst_pixmap) &&
|
|
src_vpix->backing & VMWGFX_PIX_SURFACE) {
|
|
|
|
if (!has_dirty_hw && !has_valid_hw)
|
|
return FALSE;
|
|
|
|
if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg))
|
|
return FALSE;
|
|
if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) {
|
|
vsaa->present_copy = TRUE;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
vsaa->present_copy = FALSE;
|
|
if (src_vpix != dst_vpix) {
|
|
|
|
/*
|
|
* Use hardware acceleration either if source is partially only
|
|
* in hardware, or if source is entirely in hardware and destination
|
|
* has a hardware surface.
|
|
*/
|
|
|
|
if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL)))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Determine surface formats.
|
|
*/
|
|
|
|
if (src_vpix->base.src_format == 0) {
|
|
if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
|
|
return FALSE;
|
|
} else {
|
|
if (PIXMAN_FORMAT_TYPE(src_vpix->base.src_format) != PIXMAN_TYPE_ARGB ||
|
|
!vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format))
|
|
return FALSE;
|
|
}
|
|
|
|
if (dst_vpix->base.dst_format == 0) {
|
|
if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0))
|
|
return FALSE;
|
|
} else {
|
|
if (PIXMAN_FORMAT_TYPE(dst_vpix->base.dst_format) != PIXMAN_TYPE_ARGB ||
|
|
!vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format))
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Create hardware surfaces.
|
|
*/
|
|
|
|
if (!vmwgfx_hw_commit(src_pixmap))
|
|
return FALSE;
|
|
if (!vmwgfx_hw_commit(dst_pixmap))
|
|
return FALSE;
|
|
|
|
/*
|
|
* Migrate data.
|
|
*/
|
|
|
|
if (!vmwgfx_hw_validate(src_pixmap, src_reg)) {
|
|
xa_copy_done(vsaa->xa_ctx);
|
|
xa_context_flush(vsaa->xa_ctx);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Setup copy state.
|
|
*/
|
|
|
|
if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) !=
|
|
XA_ERR_NONE)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
vmwgfx_present_done(struct vmwgfx_saa *vsaa)
|
|
{
|
|
ScreenPtr pScreen = vsaa->pScreen;
|
|
struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix;
|
|
|
|
(void) pScreen;
|
|
if (!vsaa->diff_valid)
|
|
return;
|
|
|
|
(void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id,
|
|
vsaa->xdiff, vsaa->ydiff,
|
|
&vsaa->present_region, vsaa->src_handle);
|
|
|
|
REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff);
|
|
REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage,
|
|
&vsaa->present_region);
|
|
vsaa->diff_valid = FALSE;
|
|
REGION_UNINIT(pScreen, &vsaa->present_region);
|
|
}
|
|
|
|
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)
|
|
{
|
|
int xdiff = dst_x - src_x;
|
|
int ydiff = dst_y - src_y;
|
|
BoxRec box;
|
|
RegionRec reg;
|
|
|
|
if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff)))
|
|
(void) vmwgfx_present_done(vsaa);
|
|
|
|
if (!vsaa->diff_valid) {
|
|
vsaa->xdiff = xdiff;
|
|
vsaa->ydiff = ydiff;
|
|
vsaa->diff_valid = TRUE;
|
|
}
|
|
|
|
box.x1 = src_x;
|
|
box.x2 = src_x + w;
|
|
box.y1 = src_y;
|
|
box.y2 = src_y + h;
|
|
|
|
REGION_INIT(pScreen, ®, &box, 1);
|
|
REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®);
|
|
REGION_UNINIT(pScreen, ®);
|
|
}
|
|
|
|
static void
|
|
vmwgfx_copy(struct saa_driver *driver,
|
|
int src_x,
|
|
int src_y,
|
|
int dst_x,
|
|
int dst_y,
|
|
int w,
|
|
int h)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
|
|
if (vsaa->present_copy) {
|
|
vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h);
|
|
return;
|
|
}
|
|
xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h);
|
|
}
|
|
|
|
static void
|
|
vmwgfx_copy_done(struct saa_driver *driver)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
|
|
if (vsaa->present_copy) {
|
|
vmwgfx_present_done(vsaa);
|
|
return;
|
|
}
|
|
xa_copy_done(vsaa->xa_ctx);
|
|
xa_context_flush(vsaa->xa_ctx);
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
struct vmwgfx_saa_pixmap *src_vpix;
|
|
struct vmwgfx_saa_pixmap *dst_vpix;
|
|
struct vmwgfx_saa_pixmap *mask_vpix;
|
|
Bool tmp_valid_hw;
|
|
Bool dirty_hw;
|
|
Bool valid_hw;
|
|
RegionRec empty;
|
|
struct xa_composite *xa_comp;
|
|
|
|
if (!vsaa->is_master)
|
|
return FALSE;
|
|
|
|
REGION_NULL(pScreen, &empty);
|
|
|
|
/*
|
|
* First we define our migration policy. We accelerate only if there
|
|
* are dirty hw regions to be read or if all source data is
|
|
* available in hw, and the destination has a hardware surface.
|
|
*/
|
|
dst_vpix = vmwgfx_saa_pixmap(dst_pix);
|
|
valid_hw = (dst_vpix->hw != NULL);
|
|
if (saa_op_reads_destination(op)) {
|
|
vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region,
|
|
&dirty_hw, &tmp_valid_hw);
|
|
valid_hw = (valid_hw && tmp_valid_hw);
|
|
} else {
|
|
dirty_hw = FALSE;
|
|
dst_region = ∅
|
|
}
|
|
|
|
if (src_pix && !dirty_hw) {
|
|
src_vpix = vmwgfx_saa_pixmap(src_pix);
|
|
vmwgfx_check_hw_contents(vsaa, src_vpix, src_region,
|
|
&dirty_hw, &tmp_valid_hw);
|
|
valid_hw = (valid_hw && tmp_valid_hw);
|
|
}
|
|
|
|
if (mask_pict && mask_pix && !dirty_hw) {
|
|
mask_vpix = vmwgfx_saa_pixmap(mask_pix);
|
|
vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region,
|
|
&dirty_hw, &tmp_valid_hw);
|
|
valid_hw = (valid_hw && tmp_valid_hw);
|
|
}
|
|
|
|
/*
|
|
* In rendercheck mode we try to accelerate all supported
|
|
* composite operations.
|
|
*/
|
|
|
|
if (!valid_hw && !dirty_hw && !vsaa->rendercheck)
|
|
goto out_err;
|
|
|
|
/*
|
|
* Then, setup most of the XA composite state (except hardware surfaces)
|
|
* and check whether XA can accelerate.
|
|
*/
|
|
|
|
if (!mask_pix)
|
|
mask_pict = NULL;
|
|
xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op,
|
|
src_pict, mask_pict, dst_pict);
|
|
if (!xa_comp)
|
|
goto out_err;
|
|
|
|
if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE)
|
|
goto out_err;
|
|
|
|
/*
|
|
* Check that we can create the needed hardware surfaces.
|
|
*/
|
|
if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format))
|
|
goto out_err;
|
|
if (mask_pict && mask_pix &&
|
|
!vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format))
|
|
goto out_err;
|
|
if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format))
|
|
goto out_err;
|
|
|
|
/*
|
|
* Seems OK. Commit the changes, creating hardware surfaces.
|
|
*/
|
|
if (src_pix && !vmwgfx_hw_commit(src_pix))
|
|
goto out_err;
|
|
if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix))
|
|
goto out_err;
|
|
if (!vmwgfx_hw_commit(dst_pix))
|
|
goto out_err;
|
|
|
|
/*
|
|
* Update the XA state with our hardware surfaces and
|
|
* surface formats
|
|
*/
|
|
if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix))
|
|
goto out_err;
|
|
|
|
/*
|
|
* Migrate data to surfaces.
|
|
*/
|
|
if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL))
|
|
goto out_err;
|
|
if (mask_pict && mask_pix && mask_region &&
|
|
!vmwgfx_hw_validate(mask_pix, NULL))
|
|
goto out_err;
|
|
if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL))
|
|
goto out_err;
|
|
|
|
|
|
/*
|
|
* Bind the XA state. This must be done after data migration, since
|
|
* migration may change the hardware surfaces.
|
|
*/
|
|
if (xa_composite_prepare(vsaa->xa_ctx, xa_comp))
|
|
goto out_err;
|
|
|
|
return TRUE;
|
|
|
|
out_err:
|
|
return FALSE;
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
|
|
xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y,
|
|
dst_x, dst_y, width, height);
|
|
}
|
|
|
|
static void
|
|
vmwgfx_composite_done(struct saa_driver *driver)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
|
|
xa_composite_done(vsaa->xa_ctx);
|
|
xa_context_flush(vsaa->xa_ctx);
|
|
}
|
|
|
|
static void
|
|
vmwgfx_takedown(struct saa_driver *driver)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
|
|
if (vsaa->vcomp)
|
|
vmwgfx_free_composite(vsaa->vcomp);
|
|
free(vsaa);
|
|
}
|
|
|
|
/*
|
|
* This function call originates from the damage layer (outside SAA)
|
|
* to indicate that an operation is complete, and that damage is being
|
|
* processed.
|
|
*/
|
|
static void
|
|
vmwgfx_operation_complete(struct saa_driver *driver,
|
|
PixmapPtr pixmap)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen);
|
|
|
|
/*
|
|
* Make dri2 drawables up to date, or add them to the flush list
|
|
* executed at glxWaitX(). Currently glxWaitX() is broken, so
|
|
* we flush immediately, unless we're VT-switched away, in which
|
|
* case a flush would deadlock in the kernel.
|
|
*
|
|
* For pixmaps for which vpix->hw_is_hosted is true, we can explicitly
|
|
* inform the compositor when contents has changed, so for those pixmaps
|
|
* we defer the upload until the compositor is informed, by putting
|
|
* them on the sync_x_list. Note that hw_is_dri2_fronts take precedence.
|
|
*/
|
|
if (vpix->hw && (vpix->hw_is_dri2_fronts || vpix->hw_is_hosted)) {
|
|
if (pScrn->vtSema && vpix->hw_is_dri2_fronts &&
|
|
vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) {
|
|
|
|
REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
|
|
return;
|
|
}
|
|
|
|
if (WSBMLISTEMPTY(&vpix->sync_x_head))
|
|
WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function is called by SAA to indicate that SAA has
|
|
* dirtied a region of a pixmap, either as hw (accelerated) or as
|
|
* !hw (not accelerated).
|
|
*/
|
|
static Bool
|
|
vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap,
|
|
Bool hw, RegionPtr damage)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
|
|
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
|
|
struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
|
|
|
|
/*
|
|
* Return if this is not a scanout pixmap.
|
|
*/
|
|
if (WSBMLISTEMPTY(&vpix->scanout_list))
|
|
return TRUE;
|
|
|
|
#if 0
|
|
/*
|
|
* This code can be enabled to immediately upload scanout sw
|
|
* contents to the hw surface. Otherwise this is done
|
|
* just before we call the kms update function for the hw
|
|
* surface.
|
|
*/
|
|
if (vpix->scanout_hw) {
|
|
if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage))
|
|
return FALSE;
|
|
|
|
REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow,
|
|
&spix->dirty_shadow, damage);
|
|
hw = TRUE;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Is the new scanout damage hw or sw?
|
|
*/
|
|
if (hw) {
|
|
/*
|
|
* Dump pending present into present tracking region.
|
|
*/
|
|
if (vpix->dirty_present &&
|
|
REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) {
|
|
REGION_UNION(vsaa->pScreen, vpix->dirty_present,
|
|
vpix->dirty_present, damage);
|
|
REGION_EMPTY(vsaa->pScreen, vpix->present_damage);
|
|
} else {
|
|
if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) {
|
|
RegionRec reg;
|
|
|
|
REGION_NULL(vsaa->pScreen, ®);
|
|
REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update,
|
|
damage);
|
|
if (REGION_NOTEMPTY(vsaa->pScreen, ®))
|
|
vsaa->present_flush(vsaa->pScreen);
|
|
REGION_UNINIT(pScreen, ®);
|
|
}
|
|
REGION_UNION(vsaa->pScreen, vpix->pending_present,
|
|
vpix->pending_present, damage);
|
|
if (vpix->dirty_present)
|
|
REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
|
|
vpix->dirty_present, damage);
|
|
}
|
|
} else {
|
|
if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) {
|
|
RegionRec reg;
|
|
|
|
REGION_NULL(vsaa->pScreen, ®);
|
|
REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present,
|
|
damage);
|
|
if (REGION_NOTEMPTY(vsaa->pScreen, ®))
|
|
vsaa->present_flush(vsaa->pScreen);
|
|
REGION_UNINIT(pScreen, ®);
|
|
}
|
|
REGION_UNION(vsaa->pScreen, vpix->pending_update,
|
|
vpix->pending_update, damage);
|
|
if (vpix->dirty_present)
|
|
REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
|
|
vpix->dirty_present, damage);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static const struct saa_driver vmwgfx_saa_driver = {
|
|
.saa_major = SAA_VERSION_MAJOR,
|
|
.saa_minor = SAA_VERSION_MINOR,
|
|
.pixmap_size = sizeof(struct vmwgfx_saa_pixmap),
|
|
.damage = vmwgfx_dirty,
|
|
.operation_complete = vmwgfx_operation_complete,
|
|
.download_from_hw = vmwgfx_download_from_hw,
|
|
.release_from_cpu = vmwgfx_release_from_cpu,
|
|
.sync_for_cpu = vmwgfx_sync_for_cpu,
|
|
.map = vmwgfx_map,
|
|
.unmap = vmwgfx_unmap,
|
|
.create_pixmap = vmwgfx_create_pixmap,
|
|
.destroy_pixmap = vmwgfx_destroy_pixmap,
|
|
.modify_pixmap_header = vmwgfx_modify_pixmap_header,
|
|
.copy_prepare = vmwgfx_copy_prepare,
|
|
.copy = vmwgfx_copy,
|
|
.copy_done = vmwgfx_copy_done,
|
|
.composite_prepare = vmwgfx_composite_prepare,
|
|
.composite = vmwgfx_composite,
|
|
.composite_done = vmwgfx_composite_done,
|
|
.takedown = vmwgfx_takedown,
|
|
};
|
|
|
|
|
|
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)
|
|
{
|
|
struct vmwgfx_saa *vsaa;
|
|
|
|
vsaa = calloc(1, sizeof(*vsaa));
|
|
if (!vsaa)
|
|
return FALSE;
|
|
|
|
if (xat == NULL) {
|
|
direct_presents = FALSE;
|
|
only_hw_presents = FALSE;
|
|
has_screen_targets = FALSE;
|
|
}
|
|
|
|
vsaa->pScreen = pScreen;
|
|
vsaa->xat = xat;
|
|
if (xat)
|
|
vsaa->xa_ctx = xa_context_default(xat);
|
|
vsaa->drm_fd = drm_fd;
|
|
vsaa->present_flush = present_flush;
|
|
vsaa->can_optimize_dma = TRUE;
|
|
vsaa->use_present_opt = direct_presents;
|
|
vsaa->only_hw_presents = only_hw_presents;
|
|
vsaa->rendercheck = rendercheck;
|
|
vsaa->is_master = TRUE;
|
|
vsaa->known_prime_format = FALSE;
|
|
vsaa->has_screen_targets = has_screen_targets;
|
|
WSBMINITLISTHEAD(&vsaa->sync_x_list);
|
|
WSBMINITLISTHEAD(&vsaa->pixmaps);
|
|
|
|
vsaa->driver = vmwgfx_saa_driver;
|
|
vsaa->vcomp = vmwgfx_alloc_composite();
|
|
|
|
if (!vsaa->vcomp)
|
|
vsaa->driver.composite_prepare = NULL;
|
|
|
|
if (!saa_driver_init(pScreen, &vsaa->driver))
|
|
goto out_no_saa;
|
|
|
|
return TRUE;
|
|
out_no_saa:
|
|
free(vsaa);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* *************************************************************************
|
|
* Scanout functions.
|
|
* These do not strictly belong here, but we choose to hide the scanout
|
|
* pixmap private data in the saa pixmaps. Might want to revisit this.
|
|
*/
|
|
|
|
/*
|
|
* Make sure we flush / update this scanout on next update run.
|
|
*/
|
|
|
|
void
|
|
vmwgfx_scanout_refresh(PixmapPtr pixmap)
|
|
{
|
|
ScreenPtr pScreen = pixmap->drawable.pScreen;
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
BoxRec box;
|
|
|
|
(void) pScreen;
|
|
box.x1 = 0;
|
|
box.y1 = 0;
|
|
box.x2 = pixmap->drawable.width;
|
|
box.y2 = pixmap->drawable.height;
|
|
|
|
REGION_RESET(vsaa->pScreen, vpix->pending_present, &box);
|
|
if (vpix->dirty_present)
|
|
REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
|
|
vpix->pending_present, vpix->dirty_present);
|
|
REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
|
|
vpix->pending_present, &vpix->base.dirty_shadow);
|
|
REGION_COPY(vsaa->pScreen, vpix->pending_update,
|
|
&vpix->base.dirty_shadow);
|
|
}
|
|
|
|
/*
|
|
* Take a "scanout reference" on a pixmap. If this is the first scanout
|
|
* reference, allocate resources needed for scanout, like proper
|
|
* damage tracking and kms fbs.
|
|
*/
|
|
|
|
uint32_t
|
|
vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry,
|
|
Bool scanout_equals_pixmap)
|
|
{
|
|
PixmapPtr pixmap = entry->pixmap;
|
|
struct vmwgfx_saa *vsaa =
|
|
to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
|
|
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
|
|
|
|
if (WSBMLISTEMPTY(&vpix->scanout_list)) {
|
|
uint32_t handle, dummy;
|
|
unsigned int depth;
|
|
|
|
vpix->scanout_hw = vsaa->only_hw_presents ||
|
|
(vsaa->has_screen_targets && scanout_equals_pixmap);
|
|
|
|
if (vpix->scanout_hw) {
|
|
/*
|
|
* The KMS fb will be a HW surface. Create it, add damage
|
|
* and get the handle.
|
|
*/
|
|
if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT |
|
|
XA_FLAG_RENDER_TARGET, 0, NULL))
|
|
goto out_err;
|
|
if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0)
|
|
goto out_err;
|
|
depth = xa_format_depth(xa_surface_format(vpix->hw));
|
|
|
|
} else {
|
|
/*
|
|
* The KMS fb will be a Guest Memory Region. Create it,
|
|
* add damage and get the handle.
|
|
*/
|
|
if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
|
|
goto out_err;
|
|
|
|
handle = vpix->gmr->handle;
|
|
depth = pixmap->drawable.depth;
|
|
|
|
}
|
|
|
|
if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt))
|
|
goto out_no_present;
|
|
|
|
if (drmModeAddFB(vsaa->drm_fd,
|
|
pixmap->drawable.width,
|
|
pixmap->drawable.height,
|
|
depth,
|
|
pixmap->drawable.bitsPerPixel,
|
|
pixmap->devKind,
|
|
handle,
|
|
&vpix->fb_id) != 0)
|
|
goto out_no_fb;;
|
|
}
|
|
dixPixmapGet(pixmap);
|
|
WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list);
|
|
return vpix->fb_id;
|
|
|
|
out_no_fb:
|
|
vmwgfx_pixmap_remove_present(vpix);
|
|
out_no_present:
|
|
vmwgfx_pixmap_remove_damage(pixmap);
|
|
out_err:
|
|
vpix->fb_id = -1;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Free a "scanout reference" on a pixmap. If this was the last scanout
|
|
* reference, free pixmap resources needed for scanout, like
|
|
* damage tracking and kms fbs.
|
|
*/
|
|
void
|
|
vmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry)
|
|
{
|
|
struct vmwgfx_saa *vsaa;
|
|
struct vmwgfx_saa_pixmap *vpix;
|
|
PixmapPtr pixmap = entry->pixmap;
|
|
|
|
if (!pixmap)
|
|
return;
|
|
|
|
vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
|
|
vpix = vmwgfx_saa_pixmap(pixmap);
|
|
WSBMLISTDELINIT(&entry->scanout_head);
|
|
|
|
if (WSBMLISTEMPTY(&vpix->scanout_list)) {
|
|
REGION_EMPTY(vsaa->pScreen, vpix->pending_update);
|
|
drmModeRmFB(vsaa->drm_fd, vpix->fb_id);
|
|
vpix->fb_id = -1;
|
|
vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL);
|
|
vmwgfx_pixmap_remove_present(vpix);
|
|
vmwgfx_pixmap_remove_damage(pixmap);
|
|
}
|
|
|
|
entry->pixmap = NULL;
|
|
dixPixmapPut(pixmap);
|
|
}
|
|
|
|
void
|
|
vmwgfx_saa_set_master(ScreenPtr pScreen)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
|
|
|
|
vsaa->is_master = TRUE;
|
|
vmwgfx_flush_dri2(pScreen);
|
|
}
|
|
|
|
void
|
|
vmwgfx_saa_drop_master(ScreenPtr pScreen)
|
|
{
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
|
|
struct _WsbmListHead *list;
|
|
struct vmwgfx_saa_pixmap *vpix;
|
|
struct saa_pixmap *spix;
|
|
|
|
WSBMLISTFOREACH(list, &vsaa->pixmaps) {
|
|
vpix = WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, pixmap_list);
|
|
spix = &vpix->base;
|
|
|
|
if (!vpix->hw)
|
|
continue;
|
|
|
|
(void) vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap,
|
|
&spix->dirty_hw);
|
|
REGION_EMPTY(draw->pScreen, &spix->dirty_hw);
|
|
}
|
|
|
|
vsaa->is_master = FALSE;
|
|
}
|
|
|
|
/*
|
|
* *************************************************************************
|
|
* Helpers for hosted.
|
|
*/
|
|
|
|
#if (XA_TRACKER_VERSION_MAJOR >= 2) && defined(HAVE_LIBDRM_2_4_38)
|
|
|
|
/**
|
|
* vmwgfx_saa_copy_to_surface - Copy Drawable contents to an external surface.
|
|
*
|
|
* @pDraw: Pointer to source drawable.
|
|
* @surface_fd: Prime file descriptor of external surface to copy to.
|
|
* @dst_box: BoxRec describing the destination bounding box.
|
|
* @region: Region of drawable to copy. Note: The code assumes that the
|
|
* region is relative to the drawable origin, not the underlying pixmap
|
|
* origin.
|
|
*
|
|
* Copies the contents (both software- and accelerated contents) to an
|
|
* external surface.
|
|
*/
|
|
Bool
|
|
vmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd,
|
|
const BoxRec *dst_box, RegionPtr region)
|
|
{
|
|
ScreenPtr pScreen = pDraw->pScreen;
|
|
struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
|
|
PixmapPtr src;
|
|
struct saa_pixmap *spix;
|
|
struct vmwgfx_saa_pixmap *vpix;
|
|
const BoxRec *box;
|
|
int n;
|
|
int sx, sy, dx, dy;
|
|
struct xa_surface *dst;
|
|
uint32_t handle;
|
|
Bool ret = TRUE;
|
|
RegionRec intersection;
|
|
RegionPtr copy_region = region;
|
|
|
|
if (vmwgfx_prime_fd_to_handle(vsaa->drm_fd, surface_fd, &handle) < 0)
|
|
return FALSE;
|
|
|
|
dst = xa_surface_from_handle(vsaa->xat, pDraw->width, pDraw->height,
|
|
pDraw->depth, xa_type_argb,
|
|
xa_format_unknown,
|
|
XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
|
|
handle,
|
|
(pDraw->width * pDraw->bitsPerPixel + 7) / 8);
|
|
|
|
if (!dst) {
|
|
ret = FALSE;
|
|
goto out_no_surface;
|
|
}
|
|
|
|
/*
|
|
* Assume damage region is relative to the source window.
|
|
*/
|
|
src = saa_get_pixmap(pDraw, &sx, &sy);
|
|
sx += pDraw->x;
|
|
sy += pDraw->y;
|
|
if (sx || sy)
|
|
REGION_TRANSLATE(pScreen, region, sx, sy);
|
|
|
|
dx = dst_box->x1 - sx;
|
|
dy = dst_box->y1 - sy;
|
|
|
|
spix = saa_get_saa_pixmap(src);
|
|
vpix = to_vmwgfx_saa_pixmap(spix);
|
|
|
|
/*
|
|
* Make sure software contents of the source pixmap is henceforth put
|
|
* in a GMR to avoid the extra copy in the xa DMA.
|
|
*/
|
|
vmwgfx_prefer_gmr(vsaa, src);
|
|
|
|
/*
|
|
* Determine the intersection between software contents and region to copy.
|
|
*/
|
|
|
|
if (vsaa->known_prime_format) {
|
|
REGION_NULL(pScreen, &intersection);
|
|
if (!vpix->hw)
|
|
REGION_COPY(pScreen, &intersection, region);
|
|
else if (spix->damage && REGION_NOTEMPTY(pScreen, &spix->dirty_shadow))
|
|
REGION_INTERSECT(pScreen, &intersection, region, &spix->dirty_shadow);
|
|
|
|
/*
|
|
* DMA software contents directly into the destination. Then subtract
|
|
* the region we've DMA'd from the region to copy.
|
|
*/
|
|
if (REGION_NOTEMPTY(pScreen, &intersection)) {
|
|
if (vmwgfx_saa_dma(vsaa, src, &intersection, TRUE, dx, dy, dst)) {
|
|
REGION_SUBTRACT(pScreen, &intersection, region, &intersection);
|
|
copy_region = &intersection;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!REGION_NOTEMPTY(pScreen, copy_region))
|
|
goto out_no_copy;
|
|
|
|
/*
|
|
* Copy Hardware contents to the destination
|
|
*/
|
|
box = REGION_RECTS(copy_region);
|
|
n = REGION_NUM_RECTS(copy_region);
|
|
|
|
if (!vmwgfx_hw_accel_validate(src, 0, 0, 0, copy_region)) {
|
|
ret = FALSE;
|
|
goto out_no_copy;
|
|
}
|
|
|
|
if (xa_copy_prepare(vsaa->xa_ctx, dst, vpix->hw) != XA_ERR_NONE) {
|
|
ret = FALSE;
|
|
goto out_no_copy;
|
|
}
|
|
|
|
while(n--) {
|
|
xa_copy(vsaa->xa_ctx, box->x1 + dx, box->y1 + dy, box->x1, box->y1,
|
|
box->x2 - box->x1, box->y2 - box->y1);
|
|
box++;
|
|
}
|
|
|
|
xa_copy_done(vsaa->xa_ctx);
|
|
xa_context_flush(vsaa->xa_ctx);
|
|
|
|
out_no_copy:
|
|
if (vsaa->known_prime_format)
|
|
REGION_UNINIT(pScreen, &intersection);
|
|
if (sx || sy)
|
|
REGION_TRANSLATE(pScreen, region, -sx, -sy);
|
|
xa_surface_unref(dst);
|
|
out_no_surface:
|
|
vmwgfx_prime_release_handle(vsaa->drm_fd, handle);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|