vmwgfx: Add support for XMir v2.

Use the hosted infrastructure to add support for XMir.
Helpers go in vmwgfx_saa.c.

v2: Added comments for the helpers, and added a
vmwgfx_flush_dri2 to be executed when coming back from vt switch.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
This commit is contained in:
Thomas Hellstrom
2013-12-16 06:13:25 -08:00
parent c8e1c49843
commit c020923597
9 changed files with 433 additions and 20 deletions

View File

@@ -28,5 +28,6 @@ libvmwgfx_la_SOURCES = \
vmwgfx_hosted.c \
vmwgfx_hosted.h \
vmwgfx_hosted_priv.h \
vmwgfx_xmir.c \
wsbm_util.h
endif

View File

@@ -284,7 +284,7 @@ vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf)
}
int
vmwgfx_dma(unsigned int host_x, unsigned int host_y,
vmwgfx_dma(int host_x, int host_y,
RegionPtr region, struct vmwgfx_dmabuf *buf,
uint32_t buf_pitch, uint32_t surface_handle, int to_surface)
{
@@ -500,3 +500,40 @@ vmwgfx_max_fb_size(int drm_fd, size_t *size)
return 0;
}
/**
* vmwgfx_prime_fd_to_handle - Return a TTM handle to a prime object
*
* @drm_fd: File descriptor for the drm connection.
* @prime_fd: File descriptor identifying the prime object.
* @handle: Pointer to returned TTM handle.
*
* Takes a reference on the underlying object and returns a TTM handle to it.
*/
int
vmwgfx_prime_fd_to_handle(int drm_fd, int prime_fd, uint32_t *handle)
{
*handle = 0;
return drmPrimeFDToHandle(drm_fd, prime_fd, handle);
}
/**
* vmwgfx_prime_release_handle - Release a reference on a TTM object
*
* @drm_fd: File descriptor for the drm connection.
* @handle: TTM handle as returned by vmwgfx_prime_fd_to_handle.
*
* Releases the reference obtained by vmwgfx_prime_fd_to_handle().
*/
void
vmwgfx_prime_release_handle(int drm_fd, uint32_t handle)
{
struct drm_vmw_surface_arg s_arg;
memset(&s_arg, 0, sizeof(s_arg));
s_arg.sid = handle;
(void) drmCommandWrite(drm_fd, DRM_VMW_UNREF_SURFACE, &s_arg,
sizeof(s_arg));
}

View File

@@ -60,7 +60,7 @@ extern void
vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf);
extern int
vmwgfx_dma(unsigned int host_x, unsigned int host_y,
vmwgfx_dma(int host_x, int host_y,
RegionPtr region, struct vmwgfx_dmabuf *buf,
uint32_t buf_pitch, uint32_t surface_handle, int to_surface);
@@ -84,4 +84,10 @@ vmwgfx_update_gui_layout(int drm_fd, unsigned int num_rects,
struct drm_vmw_rect *rects);
int
vmwgfx_get_param(int drm_fd, uint32_t param, uint64_t *out);
int
vmwgfx_prime_fd_to_handle(int drm_fd, int prime_fd, uint32_t *handle);
void
vmwgfx_prime_release_handle(int drm_fd, uint32_t handle);
#endif

View File

@@ -46,7 +46,9 @@
const struct vmwgfx_hosted_driver *
vmwgfx_hosted_detect(void)
{
return NULL;
const struct vmwgfx_hosted_driver *tmp = vmwgfx_xmir_detect();
return tmp;
}
/**
@@ -61,4 +63,5 @@ vmwgfx_hosted_detect(void)
void
vmwgfx_hosted_modify_flags(uint32_t *flags)
{
vmwgfx_xmir_modify_flags(flags);
}

View File

@@ -23,6 +23,7 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Thomas Hellstrom <thellstrom@vmware.com>
* Note: "Hosted" is a term stolen from the xf86-video-intel driver.
*/
#ifndef _VMWGFX_HOSTED_H

View File

@@ -31,4 +31,7 @@
#include <stdint.h>
#include "vmwgfx_hosted.h"
extern const struct vmwgfx_hosted_driver *vmwgfx_xmir_detect(void);
extern void vmwgfx_xmir_modify_flags(uint32_t *flags);
#endif

View File

@@ -282,32 +282,44 @@ static Bool
vmwgfx_saa_dma(struct vmwgfx_saa *vsaa,
PixmapPtr pixmap,
RegionPtr reg,
Bool to_hw)
Bool to_hw,
int dx,
int dy,
struct xa_surface *srf)
{
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
if (!vpix->hw || (!vpix->gmr && !vpix->malloc))
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(vpix->hw, &handle, &dummy) != 0)
if (_xa_surface_handle(srf, &handle, &dummy) != 0)
goto out_err;
if (vmwgfx_dma(0, 0, reg, vpix->gmr, pixmap->devKind, handle,
if (vmwgfx_dma(dx, dy, reg, vpix->gmr, pixmap->devKind, handle,
to_hw) != 0)
goto out_err;
} else {
void *data = vpix->malloc;
uint8_t *data = (uint8_t *) vpix->malloc;
int ret;
if (vpix->gmr) {
data = vmwgfx_dmabuf_map(vpix->gmr);
data = (uint8_t *) vmwgfx_dmabuf_map(vpix->gmr);
if (!data)
goto out_err;
}
ret = xa_surface_dma(vsaa->xa_ctx, vpix->hw, data, pixmap->devKind,
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));
@@ -315,6 +327,8 @@ vmwgfx_saa_dma(struct vmwgfx_saa *vsaa,
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;
}
@@ -353,7 +367,7 @@ vmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap,
if (!vmwgfx_pixmap_create_sw(vsaa, pixmap))
goto out_err;
if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE))
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);
@@ -368,7 +382,8 @@ 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);
return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE,
0, 0, NULL);
}
static void
@@ -753,6 +768,33 @@ vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa,
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,
@@ -786,15 +828,16 @@ vmwgfx_create_hw(struct vmwgfx_saa *vsaa,
if (!vmwgfx_pixmap_add_damage(pixmap))
goto out_no_damage;
/*
* Even if we don't have a GMR yet, indicate that when needed it
* should be created.
*/
vpix->hw = hw;
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:
@@ -1226,10 +1269,14 @@ vmwgfx_operation_complete(struct saa_driver *driver,
* 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) {
if (pScrn->vtSema &&
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);
@@ -1539,6 +1586,7 @@ 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
@@ -1563,3 +1611,134 @@ vmwgfx_saa_drop_master(ScreenPtr pScreen)
vsaa->is_master = FALSE;
}
/*
* *************************************************************************
* Helpers for hosted.
*/
#if (XA_TRACKER_VERSION_MAJOR >= 2)
/**
* 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.
* XXX: First check that the software contents is compatible with the
* external surface format, before applying this optimization.
*/
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 (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:
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

View File

@@ -52,6 +52,7 @@ struct vmwgfx_saa_pixmap {
struct xa_surface *hw;
uint32_t fb_id;
int hw_is_dri2_fronts;
Bool hw_is_hosted;
struct _WsbmListHead sync_x_head;
struct _WsbmListHead scanout_list;
struct _WsbmListHead pixmap_list;
@@ -115,6 +116,10 @@ vmwgfx_saa_set_master(ScreenPtr pScreen);
void
vmwgfx_saa_drop_master(ScreenPtr pScreen);
Bool
vmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd,
const BoxRec *dst_box, RegionPtr region);
#if (XA_TRACKER_VERSION_MAJOR <= 1) && !defined(HAVE_XA_2)
#define _xa_surface_handle(_a, _b, _c) xa_surface_handle(_a, _b, _c)

178
vmwgfx/vmwgfx_xmir.c Normal file
View File

@@ -0,0 +1,178 @@
/*
* Copyright 2013 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>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "vmwgfx_hosted_priv.h"
#include <xa_tracker.h>
#if XMIR && (XA_TRACKER_VERSION_MAJOR >= 2)
#include "vmwgfx_hosted.h"
#include "vmwgfx_saa.h"
#include <xf86Priv.h>
#include <xmir.h>
struct vmwgfx_hosted {
xmir_screen *xmir;
ScrnInfoPtr pScrn;
ScreenPtr pScreen;
};
static void
vmwgfx_xmir_copy_to_mir(xmir_window *xmir_win, RegionPtr region);
static xmir_driver vmwgfx_xmir_driver = {
XMIR_DRIVER_VERSION,
vmwgfx_xmir_copy_to_mir
};
static struct vmwgfx_hosted *
vmwgfx_xmir_create(ScrnInfoPtr pScrn)
{
struct vmwgfx_hosted *hosted;
hosted = calloc(1, sizeof(*hosted));
if (!hosted)
return NULL;
hosted->xmir = xmir_screen_create(pScrn);
if (!hosted->xmir) {
free(hosted);
return NULL;
}
hosted->pScrn = pScrn;
return hosted;
}
static void
vmwgfx_xmir_destroy(struct vmwgfx_hosted *hosted)
{
xmir_screen_destroy(hosted->xmir);
free(hosted);
}
static Bool
vmwgfx_xmir_pre_init(struct vmwgfx_hosted *hosted, int flags)
{
return xmir_screen_pre_init(hosted->pScrn, hosted->xmir,
&vmwgfx_xmir_driver);
}
static int
vmwgfx_xmir_drm_fd(struct vmwgfx_hosted *hosted, const struct pci_device *pci)
{
char bus_id[20];
snprintf(bus_id, sizeof(bus_id), "pci:%04x:%02x:%02x.%d",
pci->domain, pci->bus, pci->dev, pci->func);
return xmir_get_drm_fd(bus_id);
}
static Bool
vmwgfx_xmir_screen_init(struct vmwgfx_hosted *hosted, ScreenPtr pScreen)
{
if (!xmir_screen_init(pScreen, hosted->xmir))
return FALSE;
hosted->pScreen = pScreen;
return TRUE;
}
static void
vmwgfx_xmir_screen_close(struct vmwgfx_hosted *hosted)
{
if (hosted->pScreen)
xmir_screen_close(hosted->pScreen, hosted->xmir);
hosted->pScreen = NULL;
}
static void
vmwgfx_xmir_post_damage(struct vmwgfx_hosted *hosted)
{
xmir_screen_for_each_damaged_window(hosted->xmir, vmwgfx_xmir_copy_to_mir);
}
static int
vmwgfx_xmir_dri_auth(struct vmwgfx_hosted *hosted, ClientPtr client,
uint32_t magic)
{
return xmir_auth_drm_magic(hosted->xmir, magic);
}
static void
vmwgfx_xmir_copy_to_mir(xmir_window *xmir_win, RegionPtr region)
{
DrawablePtr pDraw = (DrawablePtr) xmir_window_to_windowptr(xmir_win);
const BoxRec *dst_box = xmir_window_get_drawable_region(xmir_win);
if (vmwgfx_saa_copy_to_surface(pDraw, xmir_window_get_fd(xmir_win),
dst_box, region))
xmir_submit_rendering_for_window(xmir_win, region);
}
static const struct vmwgfx_hosted_driver vmwgfx_hosted_xmir_driver = {
.create = vmwgfx_xmir_create,
.destroy = vmwgfx_xmir_destroy,
.drm_fd = vmwgfx_xmir_drm_fd,
.pre_init = vmwgfx_xmir_pre_init,
.screen_init = vmwgfx_xmir_screen_init,
.screen_close = vmwgfx_xmir_screen_close,
.post_damage = vmwgfx_xmir_post_damage,
.dri_auth = vmwgfx_xmir_dri_auth
};
const struct vmwgfx_hosted_driver *
vmwgfx_xmir_detect(void)
{
return (xorgMir) ? &vmwgfx_hosted_xmir_driver : NULL;
}
void vmwgfx_xmir_modify_flags(uint32_t *flags)
{
if (xorgMir)
*flags |= HW_SKIP_CONSOLE;
}
#else
const struct vmwgfx_hosted_driver *
vmwgfx_xmir_detect(void)
{
return NULL;
}
void
vmwgfx_xmir_modify_flags(uint32_t *flags)
{
}
#endif