mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
drm/vmwgfx: Add new ioctl for GB surface create and reference
New ioctls DRM_VMW_GB_SURFACE_CREATE_EXT and DRM_VMW_GB_SURFACE_REF_EXT are added which support 64-bit wide svga device surface flags, quality level and multisample pattern. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Charmaine Lee <charmainel@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
parent
397a11175f
commit
14b1c33e84
6 changed files with 437 additions and 175 deletions
|
@ -137,6 +137,12 @@
|
||||||
#define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \
|
#define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \
|
||||||
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \
|
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \
|
||||||
struct drm_vmw_context_arg)
|
struct drm_vmw_context_arg)
|
||||||
|
#define DRM_IOCTL_VMW_GB_SURFACE_CREATE_EXT \
|
||||||
|
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE_EXT, \
|
||||||
|
union drm_vmw_gb_surface_create_ext_arg)
|
||||||
|
#define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \
|
||||||
|
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \
|
||||||
|
union drm_vmw_gb_surface_reference_ext_arg)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The core DRM version of this macro doesn't account for
|
* The core DRM version of this macro doesn't account for
|
||||||
|
@ -224,6 +230,12 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
|
||||||
VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT,
|
VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT,
|
||||||
vmw_extended_context_define_ioctl,
|
vmw_extended_context_define_ioctl,
|
||||||
DRM_AUTH | DRM_RENDER_ALLOW),
|
DRM_AUTH | DRM_RENDER_ALLOW),
|
||||||
|
VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT,
|
||||||
|
vmw_gb_surface_define_ext_ioctl,
|
||||||
|
DRM_AUTH | DRM_RENDER_ALLOW),
|
||||||
|
VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT,
|
||||||
|
vmw_gb_surface_reference_ext_ioctl,
|
||||||
|
DRM_AUTH | DRM_RENDER_ALLOW),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pci_device_id vmw_pci_id_list[] = {
|
static const struct pci_device_id vmw_pci_id_list[] = {
|
||||||
|
|
|
@ -1087,7 +1087,15 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
|
||||||
uint32_t multisample_count,
|
uint32_t multisample_count,
|
||||||
uint32_t array_size,
|
uint32_t array_size,
|
||||||
struct drm_vmw_size size,
|
struct drm_vmw_size size,
|
||||||
|
SVGA3dMSPattern multisample_pattern,
|
||||||
|
SVGA3dMSQualityLevel quality_level,
|
||||||
struct vmw_surface **srf_out);
|
struct vmw_surface **srf_out);
|
||||||
|
extern int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev,
|
||||||
|
void *data,
|
||||||
|
struct drm_file *file_priv);
|
||||||
|
extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev,
|
||||||
|
void *data,
|
||||||
|
struct drm_file *file_priv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shader management - vmwgfx_shader.c
|
* Shader management - vmwgfx_shader.c
|
||||||
|
|
|
@ -1246,6 +1246,8 @@ static int vmw_create_bo_proxy(struct drm_device *dev,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
content_base_size,
|
content_base_size,
|
||||||
|
SVGA3D_MS_PATTERN_NONE,
|
||||||
|
SVGA3D_MS_QUALITY_NONE,
|
||||||
srf_out);
|
srf_out);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DRM_ERROR("Failed to allocate proxy content buffer\n");
|
DRM_ERROR("Failed to allocate proxy content buffer\n");
|
||||||
|
|
|
@ -1188,6 +1188,8 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
|
||||||
content_srf.multisample_count,
|
content_srf.multisample_count,
|
||||||
0,
|
0,
|
||||||
display_base_size,
|
display_base_size,
|
||||||
|
content_srf.multisample_pattern,
|
||||||
|
content_srf.quality_level,
|
||||||
&vps->surf);
|
&vps->surf);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
DRM_ERROR("Couldn't allocate STDU surface.\n");
|
DRM_ERROR("Couldn't allocate STDU surface.\n");
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
#include "vmwgfx_binding.h"
|
#include "vmwgfx_binding.h"
|
||||||
#include "device_include/svga3d_surfacedefs.h"
|
#include "device_include/svga3d_surfacedefs.h"
|
||||||
|
|
||||||
|
#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32)
|
||||||
|
#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32)
|
||||||
|
#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
|
||||||
|
(svga3d_flags & ((uint64_t)U32_MAX))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct vmw_user_surface - User-space visible surface resource
|
* struct vmw_user_surface - User-space visible surface resource
|
||||||
|
@ -81,7 +85,16 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res,
|
||||||
bool readback,
|
bool readback,
|
||||||
struct ttm_validate_buffer *val_buf);
|
struct ttm_validate_buffer *val_buf);
|
||||||
static int vmw_gb_surface_destroy(struct vmw_resource *res);
|
static int vmw_gb_surface_destroy(struct vmw_resource *res);
|
||||||
|
static int
|
||||||
|
vmw_gb_surface_define_internal(struct drm_device *dev,
|
||||||
|
struct drm_vmw_gb_surface_create_ext_req *req,
|
||||||
|
struct drm_vmw_gb_surface_create_rep *rep,
|
||||||
|
struct drm_file *file_priv);
|
||||||
|
static int
|
||||||
|
vmw_gb_surface_reference_internal(struct drm_device *dev,
|
||||||
|
struct drm_vmw_surface_arg *req,
|
||||||
|
struct drm_vmw_gb_surface_ref_ext_rep *rep,
|
||||||
|
struct drm_file *file_priv);
|
||||||
|
|
||||||
static const struct vmw_user_resource_conv user_surface_conv = {
|
static const struct vmw_user_resource_conv user_surface_conv = {
|
||||||
.object_type = VMW_RES_SURFACE,
|
.object_type = VMW_RES_SURFACE,
|
||||||
|
@ -1298,117 +1311,19 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res)
|
||||||
int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
|
int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
struct vmw_private *dev_priv = vmw_priv(dev);
|
|
||||||
struct vmw_user_surface *user_srf;
|
|
||||||
struct vmw_surface *srf;
|
|
||||||
struct vmw_resource *res;
|
|
||||||
struct vmw_resource *tmp;
|
|
||||||
union drm_vmw_gb_surface_create_arg *arg =
|
union drm_vmw_gb_surface_create_arg *arg =
|
||||||
(union drm_vmw_gb_surface_create_arg *)data;
|
(union drm_vmw_gb_surface_create_arg *)data;
|
||||||
struct drm_vmw_gb_surface_create_req *req = &arg->req;
|
|
||||||
struct drm_vmw_gb_surface_create_rep *rep = &arg->rep;
|
struct drm_vmw_gb_surface_create_rep *rep = &arg->rep;
|
||||||
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
struct drm_vmw_gb_surface_create_ext_req req_ext;
|
||||||
int ret;
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t backup_handle = 0;
|
|
||||||
|
|
||||||
if (req->multisample_count != 0)
|
req_ext.base = arg->req;
|
||||||
return -EINVAL;
|
req_ext.version = drm_vmw_gb_surface_v1;
|
||||||
|
req_ext.svga3d_flags_upper_32_bits = 0;
|
||||||
|
req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE;
|
||||||
|
req_ext.quality_level = SVGA3D_MS_QUALITY_NONE;
|
||||||
|
req_ext.must_be_zero = 0;
|
||||||
|
|
||||||
if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS)
|
return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (unlikely(vmw_user_surface_size == 0))
|
|
||||||
vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
|
|
||||||
128;
|
|
||||||
|
|
||||||
size = vmw_user_surface_size + 128;
|
|
||||||
|
|
||||||
/* Define a surface based on the parameters. */
|
|
||||||
ret = vmw_surface_gb_priv_define(dev,
|
|
||||||
size,
|
|
||||||
(SVGA3dSurfaceAllFlags)req->svga3d_flags,
|
|
||||||
req->format,
|
|
||||||
req->drm_surface_flags & drm_vmw_surface_flag_scanout,
|
|
||||||
req->mip_levels,
|
|
||||||
req->multisample_count,
|
|
||||||
req->array_size,
|
|
||||||
req->base_size,
|
|
||||||
&srf);
|
|
||||||
if (unlikely(ret != 0))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
user_srf = container_of(srf, struct vmw_user_surface, srf);
|
|
||||||
if (drm_is_primary_client(file_priv))
|
|
||||||
user_srf->master = drm_master_get(file_priv->master);
|
|
||||||
|
|
||||||
ret = ttm_read_lock(&dev_priv->reservation_sem, true);
|
|
||||||
if (unlikely(ret != 0))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
res = &user_srf->srf.res;
|
|
||||||
|
|
||||||
|
|
||||||
if (req->buffer_handle != SVGA3D_INVALID_ID) {
|
|
||||||
ret = vmw_user_bo_lookup(tfile, req->buffer_handle,
|
|
||||||
&res->backup,
|
|
||||||
&user_srf->backup_base);
|
|
||||||
if (ret == 0) {
|
|
||||||
if (res->backup->base.num_pages * PAGE_SIZE <
|
|
||||||
res->backup_size) {
|
|
||||||
DRM_ERROR("Surface backup buffer is too small.\n");
|
|
||||||
vmw_bo_unreference(&res->backup);
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out_unlock;
|
|
||||||
} else {
|
|
||||||
backup_handle = req->buffer_handle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer)
|
|
||||||
ret = vmw_user_bo_alloc(dev_priv, tfile,
|
|
||||||
res->backup_size,
|
|
||||||
req->drm_surface_flags &
|
|
||||||
drm_vmw_surface_flag_shareable,
|
|
||||||
&backup_handle,
|
|
||||||
&res->backup,
|
|
||||||
&user_srf->backup_base);
|
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
|
||||||
vmw_resource_unreference(&res);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = vmw_resource_reference(res);
|
|
||||||
ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
|
|
||||||
req->drm_surface_flags &
|
|
||||||
drm_vmw_surface_flag_shareable,
|
|
||||||
VMW_RES_SURFACE,
|
|
||||||
&vmw_user_surface_base_release, NULL);
|
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
|
||||||
vmw_resource_unreference(&tmp);
|
|
||||||
vmw_resource_unreference(&res);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
rep->handle = user_srf->prime.base.hash.key;
|
|
||||||
rep->backup_size = res->backup_size;
|
|
||||||
if (res->backup) {
|
|
||||||
rep->buffer_map_handle =
|
|
||||||
drm_vma_node_offset_addr(&res->backup->base.vma_node);
|
|
||||||
rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE;
|
|
||||||
rep->buffer_handle = backup_handle;
|
|
||||||
} else {
|
|
||||||
rep->buffer_map_handle = 0;
|
|
||||||
rep->buffer_size = 0;
|
|
||||||
rep->buffer_handle = SVGA3D_INVALID_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
vmw_resource_unreference(&res);
|
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
ttm_read_unlock(&dev_priv->reservation_sem);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1422,60 +1337,20 @@ out_unlock:
|
||||||
int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
|
int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
struct vmw_private *dev_priv = vmw_priv(dev);
|
|
||||||
union drm_vmw_gb_surface_reference_arg *arg =
|
union drm_vmw_gb_surface_reference_arg *arg =
|
||||||
(union drm_vmw_gb_surface_reference_arg *)data;
|
(union drm_vmw_gb_surface_reference_arg *)data;
|
||||||
struct drm_vmw_surface_arg *req = &arg->req;
|
struct drm_vmw_surface_arg *req = &arg->req;
|
||||||
struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep;
|
struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep;
|
||||||
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
struct drm_vmw_gb_surface_ref_ext_rep rep_ext;
|
||||||
struct vmw_surface *srf;
|
int ret;
|
||||||
struct vmw_user_surface *user_srf;
|
|
||||||
struct ttm_base_object *base;
|
ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv);
|
||||||
uint32_t backup_handle;
|
|
||||||
int ret = -EINVAL;
|
|
||||||
|
|
||||||
ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
|
|
||||||
req->handle_type, &base);
|
|
||||||
if (unlikely(ret != 0))
|
if (unlikely(ret != 0))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
user_srf = container_of(base, struct vmw_user_surface, prime.base);
|
rep->creq = rep_ext.creq.base;
|
||||||
srf = &user_srf->srf;
|
rep->crep = rep_ext.crep;
|
||||||
if (!srf->res.backup) {
|
|
||||||
DRM_ERROR("Shared GB surface is missing a backup buffer.\n");
|
|
||||||
goto out_bad_resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */
|
|
||||||
ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle);
|
|
||||||
mutex_unlock(&dev_priv->cmdbuf_mutex);
|
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
|
||||||
DRM_ERROR("Could not add a reference to a GB surface "
|
|
||||||
"backup buffer.\n");
|
|
||||||
(void) ttm_ref_object_base_unref(tfile, base->hash.key,
|
|
||||||
TTM_REF_USAGE);
|
|
||||||
goto out_bad_resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
rep->creq.svga3d_flags = (uint32_t)srf->flags;
|
|
||||||
rep->creq.format = srf->format;
|
|
||||||
rep->creq.mip_levels = srf->mip_levels[0];
|
|
||||||
rep->creq.drm_surface_flags = 0;
|
|
||||||
rep->creq.multisample_count = srf->multisample_count;
|
|
||||||
rep->creq.autogen_filter = srf->autogen_filter;
|
|
||||||
rep->creq.array_size = srf->array_size;
|
|
||||||
rep->creq.buffer_handle = backup_handle;
|
|
||||||
rep->creq.base_size = srf->base_size;
|
|
||||||
rep->crep.handle = user_srf->prime.base.hash.key;
|
|
||||||
rep->crep.backup_size = srf->res.backup_size;
|
|
||||||
rep->crep.buffer_handle = backup_handle;
|
|
||||||
rep->crep.buffer_map_handle =
|
|
||||||
drm_vma_node_offset_addr(&srf->res.backup->base.vma_node);
|
|
||||||
rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE;
|
|
||||||
|
|
||||||
out_bad_resource:
|
|
||||||
ttm_base_object_unref(&base);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1493,6 +1368,8 @@ out_bad_resource:
|
||||||
* @multisample_count:
|
* @multisample_count:
|
||||||
* @array_size: Surface array size.
|
* @array_size: Surface array size.
|
||||||
* @size: width, heigh, depth of the surface requested
|
* @size: width, heigh, depth of the surface requested
|
||||||
|
* @multisample_pattern: Multisampling pattern when msaa is supported
|
||||||
|
* @quality_level: Precision settings
|
||||||
* @user_srf_out: allocated user_srf. Set to NULL on failure.
|
* @user_srf_out: allocated user_srf. Set to NULL on failure.
|
||||||
*
|
*
|
||||||
* GB surfaces allocated by this function will not have a user mode handle, and
|
* GB surfaces allocated by this function will not have a user mode handle, and
|
||||||
|
@ -1509,6 +1386,8 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
|
||||||
uint32_t multisample_count,
|
uint32_t multisample_count,
|
||||||
uint32_t array_size,
|
uint32_t array_size,
|
||||||
struct drm_vmw_size size,
|
struct drm_vmw_size size,
|
||||||
|
SVGA3dMSPattern multisample_pattern,
|
||||||
|
SVGA3dMSQualityLevel quality_level,
|
||||||
struct vmw_surface **srf_out)
|
struct vmw_surface **srf_out)
|
||||||
{
|
{
|
||||||
struct vmw_private *dev_priv = vmw_priv(dev);
|
struct vmw_private *dev_priv = vmw_priv(dev);
|
||||||
|
@ -1519,7 +1398,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
|
||||||
};
|
};
|
||||||
struct vmw_surface *srf;
|
struct vmw_surface *srf;
|
||||||
int ret;
|
int ret;
|
||||||
u32 num_layers;
|
u32 num_layers = 1;
|
||||||
|
|
||||||
*srf_out = NULL;
|
*srf_out = NULL;
|
||||||
|
|
||||||
|
@ -1594,15 +1473,13 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
|
||||||
srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
|
srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
|
||||||
srf->array_size = array_size;
|
srf->array_size = array_size;
|
||||||
srf->multisample_count = multisample_count;
|
srf->multisample_count = multisample_count;
|
||||||
srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE;
|
srf->multisample_pattern = multisample_pattern;
|
||||||
srf->quality_level = SVGA3D_MS_QUALITY_NONE;
|
srf->quality_level = quality_level;
|
||||||
|
|
||||||
if (array_size)
|
if (array_size)
|
||||||
num_layers = array_size;
|
num_layers = array_size;
|
||||||
else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP)
|
else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP)
|
||||||
num_layers = SVGA3D_MAX_SURFACE_FACES;
|
num_layers = SVGA3D_MAX_SURFACE_FACES;
|
||||||
else
|
|
||||||
num_layers = 1;
|
|
||||||
|
|
||||||
srf->res.backup_size =
|
srf->res.backup_size =
|
||||||
svga3dsurface_get_serialized_size(srf->format,
|
svga3dsurface_get_serialized_size(srf->format,
|
||||||
|
@ -1633,3 +1510,262 @@ out_unlock:
|
||||||
ttm_read_unlock(&dev_priv->reservation_sem);
|
ttm_read_unlock(&dev_priv->reservation_sem);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_gb_surface_define_ext_ioctl - Ioctl function implementing
|
||||||
|
* the user surface define functionality.
|
||||||
|
*
|
||||||
|
* @dev: Pointer to a struct drm_device.
|
||||||
|
* @data: Pointer to data copied from / to user-space.
|
||||||
|
* @file_priv: Pointer to a drm file private structure.
|
||||||
|
*/
|
||||||
|
int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
union drm_vmw_gb_surface_create_ext_arg *arg =
|
||||||
|
(union drm_vmw_gb_surface_create_ext_arg *)data;
|
||||||
|
struct drm_vmw_gb_surface_create_ext_req *req = &arg->req;
|
||||||
|
struct drm_vmw_gb_surface_create_rep *rep = &arg->rep;
|
||||||
|
|
||||||
|
return vmw_gb_surface_define_internal(dev, req, rep, file_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing
|
||||||
|
* the user surface reference functionality.
|
||||||
|
*
|
||||||
|
* @dev: Pointer to a struct drm_device.
|
||||||
|
* @data: Pointer to data copied from / to user-space.
|
||||||
|
* @file_priv: Pointer to a drm file private structure.
|
||||||
|
*/
|
||||||
|
int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
union drm_vmw_gb_surface_reference_ext_arg *arg =
|
||||||
|
(union drm_vmw_gb_surface_reference_ext_arg *)data;
|
||||||
|
struct drm_vmw_surface_arg *req = &arg->req;
|
||||||
|
struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep;
|
||||||
|
|
||||||
|
return vmw_gb_surface_reference_internal(dev, req, rep, file_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_gb_surface_define_internal - Ioctl function implementing
|
||||||
|
* the user surface define functionality.
|
||||||
|
*
|
||||||
|
* @dev: Pointer to a struct drm_device.
|
||||||
|
* @req: Request argument from user-space.
|
||||||
|
* @rep: Response argument to user-space.
|
||||||
|
* @file_priv: Pointer to a drm file private structure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vmw_gb_surface_define_internal(struct drm_device *dev,
|
||||||
|
struct drm_vmw_gb_surface_create_ext_req *req,
|
||||||
|
struct drm_vmw_gb_surface_create_rep *rep,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct vmw_private *dev_priv = vmw_priv(dev);
|
||||||
|
struct vmw_user_surface *user_srf;
|
||||||
|
struct vmw_surface *srf;
|
||||||
|
struct vmw_resource *res;
|
||||||
|
struct vmw_resource *tmp;
|
||||||
|
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
||||||
|
int ret;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t backup_handle = 0;
|
||||||
|
SVGA3dSurfaceAllFlags svga3d_flags_64 =
|
||||||
|
SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits,
|
||||||
|
req->base.svga3d_flags);
|
||||||
|
|
||||||
|
if (!dev_priv->has_sm4_1) {
|
||||||
|
/*
|
||||||
|
* If SM4_1 is not support then cannot send 64-bit flag to
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
if (req->svga3d_flags_upper_32_bits != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (req->base.multisample_count != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (req->quality_level != SVGA3D_MS_QUALITY_NONE)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (unlikely(vmw_user_surface_size == 0))
|
||||||
|
vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
|
||||||
|
128;
|
||||||
|
|
||||||
|
size = vmw_user_surface_size + 128;
|
||||||
|
|
||||||
|
/* Define a surface based on the parameters. */
|
||||||
|
ret = vmw_surface_gb_priv_define(dev,
|
||||||
|
size,
|
||||||
|
svga3d_flags_64,
|
||||||
|
req->base.format,
|
||||||
|
req->base.drm_surface_flags &
|
||||||
|
drm_vmw_surface_flag_scanout,
|
||||||
|
req->base.mip_levels,
|
||||||
|
req->base.multisample_count,
|
||||||
|
req->base.array_size,
|
||||||
|
req->base.base_size,
|
||||||
|
req->multisample_pattern,
|
||||||
|
req->quality_level,
|
||||||
|
&srf);
|
||||||
|
if (unlikely(ret != 0))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
user_srf = container_of(srf, struct vmw_user_surface, srf);
|
||||||
|
if (drm_is_primary_client(file_priv))
|
||||||
|
user_srf->master = drm_master_get(file_priv->master);
|
||||||
|
|
||||||
|
ret = ttm_read_lock(&dev_priv->reservation_sem, true);
|
||||||
|
if (unlikely(ret != 0))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
res = &user_srf->srf.res;
|
||||||
|
|
||||||
|
if (req->base.buffer_handle != SVGA3D_INVALID_ID) {
|
||||||
|
ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle,
|
||||||
|
&res->backup,
|
||||||
|
&user_srf->backup_base);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (res->backup->base.num_pages * PAGE_SIZE <
|
||||||
|
res->backup_size) {
|
||||||
|
DRM_ERROR("Surface backup buffer too small.\n");
|
||||||
|
vmw_bo_unreference(&res->backup);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_unlock;
|
||||||
|
} else {
|
||||||
|
backup_handle = req->base.buffer_handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (req->base.drm_surface_flags &
|
||||||
|
drm_vmw_surface_flag_create_buffer)
|
||||||
|
ret = vmw_user_bo_alloc(dev_priv, tfile,
|
||||||
|
res->backup_size,
|
||||||
|
req->base.drm_surface_flags &
|
||||||
|
drm_vmw_surface_flag_shareable,
|
||||||
|
&backup_handle,
|
||||||
|
&res->backup,
|
||||||
|
&user_srf->backup_base);
|
||||||
|
|
||||||
|
if (unlikely(ret != 0)) {
|
||||||
|
vmw_resource_unreference(&res);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = vmw_resource_reference(res);
|
||||||
|
ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
|
||||||
|
req->base.drm_surface_flags &
|
||||||
|
drm_vmw_surface_flag_shareable,
|
||||||
|
VMW_RES_SURFACE,
|
||||||
|
&vmw_user_surface_base_release, NULL);
|
||||||
|
|
||||||
|
if (unlikely(ret != 0)) {
|
||||||
|
vmw_resource_unreference(&tmp);
|
||||||
|
vmw_resource_unreference(&res);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
rep->handle = user_srf->prime.base.hash.key;
|
||||||
|
rep->backup_size = res->backup_size;
|
||||||
|
if (res->backup) {
|
||||||
|
rep->buffer_map_handle =
|
||||||
|
drm_vma_node_offset_addr(&res->backup->base.vma_node);
|
||||||
|
rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE;
|
||||||
|
rep->buffer_handle = backup_handle;
|
||||||
|
} else {
|
||||||
|
rep->buffer_map_handle = 0;
|
||||||
|
rep->buffer_size = 0;
|
||||||
|
rep->buffer_handle = SVGA3D_INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmw_resource_unreference(&res);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
ttm_read_unlock(&dev_priv->reservation_sem);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmw_gb_surface_reference_internal - Ioctl function implementing
|
||||||
|
* the user surface reference functionality.
|
||||||
|
*
|
||||||
|
* @dev: Pointer to a struct drm_device.
|
||||||
|
* @req: Pointer to user-space request surface arg.
|
||||||
|
* @rep: Pointer to response to user-space.
|
||||||
|
* @file_priv: Pointer to a drm file private structure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vmw_gb_surface_reference_internal(struct drm_device *dev,
|
||||||
|
struct drm_vmw_surface_arg *req,
|
||||||
|
struct drm_vmw_gb_surface_ref_ext_rep *rep,
|
||||||
|
struct drm_file *file_priv)
|
||||||
|
{
|
||||||
|
struct vmw_private *dev_priv = vmw_priv(dev);
|
||||||
|
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
|
||||||
|
struct vmw_surface *srf;
|
||||||
|
struct vmw_user_surface *user_srf;
|
||||||
|
struct ttm_base_object *base;
|
||||||
|
uint32_t backup_handle;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
|
||||||
|
req->handle_type, &base);
|
||||||
|
if (unlikely(ret != 0))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
user_srf = container_of(base, struct vmw_user_surface, prime.base);
|
||||||
|
srf = &user_srf->srf;
|
||||||
|
if (!srf->res.backup) {
|
||||||
|
DRM_ERROR("Shared GB surface is missing a backup buffer.\n");
|
||||||
|
goto out_bad_resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */
|
||||||
|
ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle);
|
||||||
|
mutex_unlock(&dev_priv->cmdbuf_mutex);
|
||||||
|
|
||||||
|
if (unlikely(ret != 0)) {
|
||||||
|
DRM_ERROR("Could not add a reference to a GB surface "
|
||||||
|
"backup buffer.\n");
|
||||||
|
(void) ttm_ref_object_base_unref(tfile, base->hash.key,
|
||||||
|
TTM_REF_USAGE);
|
||||||
|
goto out_bad_resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(srf->flags);
|
||||||
|
rep->creq.base.format = srf->format;
|
||||||
|
rep->creq.base.mip_levels = srf->mip_levels[0];
|
||||||
|
rep->creq.base.drm_surface_flags = 0;
|
||||||
|
rep->creq.base.multisample_count = srf->multisample_count;
|
||||||
|
rep->creq.base.autogen_filter = srf->autogen_filter;
|
||||||
|
rep->creq.base.array_size = srf->array_size;
|
||||||
|
rep->creq.base.buffer_handle = backup_handle;
|
||||||
|
rep->creq.base.base_size = srf->base_size;
|
||||||
|
rep->crep.handle = user_srf->prime.base.hash.key;
|
||||||
|
rep->crep.backup_size = srf->res.backup_size;
|
||||||
|
rep->crep.buffer_handle = backup_handle;
|
||||||
|
rep->crep.buffer_map_handle =
|
||||||
|
drm_vma_node_offset_addr(&srf->res.backup->base.vma_node);
|
||||||
|
rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE;
|
||||||
|
|
||||||
|
rep->creq.version = drm_vmw_gb_surface_v1;
|
||||||
|
rep->creq.svga3d_flags_upper_32_bits =
|
||||||
|
SVGA3D_FLAGS_UPPER_32(srf->flags);
|
||||||
|
rep->creq.multisample_pattern = srf->multisample_pattern;
|
||||||
|
rep->creq.quality_level = srf->quality_level;
|
||||||
|
rep->creq.must_be_zero = 0;
|
||||||
|
|
||||||
|
out_bad_resource:
|
||||||
|
ttm_base_object_unref(&base);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ extern "C" {
|
||||||
#define DRM_VMW_GB_SURFACE_REF 24
|
#define DRM_VMW_GB_SURFACE_REF 24
|
||||||
#define DRM_VMW_SYNCCPU 25
|
#define DRM_VMW_SYNCCPU 25
|
||||||
#define DRM_VMW_CREATE_EXTENDED_CONTEXT 26
|
#define DRM_VMW_CREATE_EXTENDED_CONTEXT 26
|
||||||
|
#define DRM_VMW_GB_SURFACE_CREATE_EXT 27
|
||||||
|
#define DRM_VMW_GB_SURFACE_REF_EXT 28
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/**
|
/**
|
||||||
|
@ -1105,6 +1107,106 @@ struct drm_vmw_handle_close_arg {
|
||||||
};
|
};
|
||||||
#define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg
|
#define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/**
|
||||||
|
* DRM_VMW_GB_SURFACE_CREATE_EXT - Create a host guest-backed surface.
|
||||||
|
*
|
||||||
|
* Allocates a surface handle and queues a create surface command
|
||||||
|
* for the host on the first use of the surface. The surface ID can
|
||||||
|
* be used as the surface ID in commands referencing the surface.
|
||||||
|
*
|
||||||
|
* This new command extends DRM_VMW_GB_SURFACE_CREATE by adding version
|
||||||
|
* parameter and 64 bit svga flag.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum drm_vmw_surface_version
|
||||||
|
*
|
||||||
|
* @drm_vmw_surface_gb_v1: Corresponds to current gb surface format with
|
||||||
|
* svga3d surface flags split into 2, upper half and lower half.
|
||||||
|
*/
|
||||||
|
enum drm_vmw_surface_version {
|
||||||
|
drm_vmw_gb_surface_v1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct drm_vmw_gb_surface_create_ext_req
|
||||||
|
*
|
||||||
|
* @base: Surface create parameters.
|
||||||
|
* @version: Version of surface create ioctl.
|
||||||
|
* @svga3d_flags_upper_32_bits: Upper 32 bits of svga3d flags.
|
||||||
|
* @multisample_pattern: Multisampling pattern when msaa is supported.
|
||||||
|
* @quality_level: Precision settings for each sample.
|
||||||
|
* @must_be_zero: Reserved for future usage.
|
||||||
|
*
|
||||||
|
* Input argument to the DRM_VMW_GB_SURFACE_CREATE_EXT Ioctl.
|
||||||
|
* Part of output argument for the DRM_VMW_GB_SURFACE_REF_EXT Ioctl.
|
||||||
|
*/
|
||||||
|
struct drm_vmw_gb_surface_create_ext_req {
|
||||||
|
struct drm_vmw_gb_surface_create_req base;
|
||||||
|
enum drm_vmw_surface_version version;
|
||||||
|
uint32_t svga3d_flags_upper_32_bits;
|
||||||
|
SVGA3dMSPattern multisample_pattern;
|
||||||
|
SVGA3dMSQualityLevel quality_level;
|
||||||
|
uint64_t must_be_zero;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* union drm_vmw_gb_surface_create_ext_arg
|
||||||
|
*
|
||||||
|
* @req: Input argument as described above.
|
||||||
|
* @rep: Output argument as described above.
|
||||||
|
*
|
||||||
|
* Argument to the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl.
|
||||||
|
*/
|
||||||
|
union drm_vmw_gb_surface_create_ext_arg {
|
||||||
|
struct drm_vmw_gb_surface_create_rep rep;
|
||||||
|
struct drm_vmw_gb_surface_create_ext_req req;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/**
|
||||||
|
* DRM_VMW_GB_SURFACE_REF_EXT - Reference a host surface.
|
||||||
|
*
|
||||||
|
* Puts a reference on a host surface with a given handle, as previously
|
||||||
|
* returned by the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl.
|
||||||
|
* A reference will make sure the surface isn't destroyed while we hold
|
||||||
|
* it and will allow the calling client to use the surface handle in
|
||||||
|
* the command stream.
|
||||||
|
*
|
||||||
|
* On successful return, the Ioctl returns the surface information given
|
||||||
|
* to and returned from the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct drm_vmw_gb_surface_ref_ext_rep
|
||||||
|
*
|
||||||
|
* @creq: The data used as input when the surface was created, as described
|
||||||
|
* above at "struct drm_vmw_gb_surface_create_ext_req"
|
||||||
|
* @crep: Additional data output when the surface was created, as described
|
||||||
|
* above at "struct drm_vmw_gb_surface_create_rep"
|
||||||
|
*
|
||||||
|
* Output Argument to the DRM_VMW_GB_SURFACE_REF_EXT ioctl.
|
||||||
|
*/
|
||||||
|
struct drm_vmw_gb_surface_ref_ext_rep {
|
||||||
|
struct drm_vmw_gb_surface_create_ext_req creq;
|
||||||
|
struct drm_vmw_gb_surface_create_rep crep;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* union drm_vmw_gb_surface_reference_ext_arg
|
||||||
|
*
|
||||||
|
* @req: Input data as described above at "struct drm_vmw_surface_arg"
|
||||||
|
* @rep: Output data as described above at
|
||||||
|
* "struct drm_vmw_gb_surface_ref_ext_rep"
|
||||||
|
*
|
||||||
|
* Argument to the DRM_VMW_GB_SURFACE_REF Ioctl.
|
||||||
|
*/
|
||||||
|
union drm_vmw_gb_surface_reference_ext_arg {
|
||||||
|
struct drm_vmw_gb_surface_ref_ext_rep rep;
|
||||||
|
struct drm_vmw_surface_arg req;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue