Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5bde956 authored by Thomas Hellstrom's avatar Thomas Hellstrom
Browse files

drm/vmwgfx: Emulate legacy shaders on guest-backed devices v2



Command stream legacy shader creation and destruction is replaced by
NOPs in the command stream, and instead guest-backed shaders are created
and destroyed as part of the command validation process.

v2: Removed some stray debug messages.

Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: default avatarJakob Bornecrantz <jakob@vmware.com>
parent c1a21373
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -941,6 +941,7 @@ static void vmw_postclose(struct drm_device *dev,
		drm_master_put(&vmw_fp->locked_master);
	}

	vmw_compat_shader_man_destroy(vmw_fp->shman);
	ttm_object_file_release(&vmw_fp->tfile);
	kfree(vmw_fp);
}
@@ -960,11 +961,17 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
	if (unlikely(vmw_fp->tfile == NULL))
		goto out_no_tfile;

	vmw_fp->shman = vmw_compat_shader_man_create(dev_priv);
	if (IS_ERR(vmw_fp->shman))
		goto out_no_shman;

	file_priv->driver_priv = vmw_fp;
	dev_priv->bdev.dev_mapping = dev->dev_mapping;

	return 0;

out_no_shman:
	ttm_object_file_release(&vmw_fp->tfile);
out_no_tfile:
	kfree(vmw_fp);
	return ret;
+28 −1
Original line number Diff line number Diff line
@@ -75,10 +75,14 @@
#define VMW_RES_FENCE ttm_driver_type3
#define VMW_RES_SHADER ttm_driver_type4

struct vmw_compat_shader_manager;

struct vmw_fpriv {
	struct drm_master *locked_master;
	struct ttm_object_file *tfile;
	struct list_head fence_events;
	bool gb_aware;
	struct vmw_compat_shader_manager *shman;
};

struct vmw_dma_buffer {
@@ -318,7 +322,7 @@ struct vmw_sw_context{
	struct drm_open_hash res_ht;
	bool res_ht_initialized;
	bool kernel; /**< is the called made from the kernel */
	struct ttm_object_file *tfile;
	struct vmw_fpriv *fp;
	struct list_head validate_nodes;
	struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS];
	uint32_t cur_reloc;
@@ -336,6 +340,7 @@ struct vmw_sw_context{
	bool needs_post_query_barrier;
	struct vmw_resource *error_resource;
	struct vmw_ctx_binding_state staged_bindings;
	struct list_head staged_shaders;
};

struct vmw_legacy_display;
@@ -991,6 +996,28 @@ extern int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
				   struct drm_file *file_priv);
extern int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
				    struct drm_file *file_priv);
extern int vmw_compat_shader_lookup(struct vmw_compat_shader_manager *man,
				    SVGA3dShaderType shader_type,
				    u32 *user_key);
extern void vmw_compat_shaders_commit(struct vmw_compat_shader_manager *man,
				      struct list_head *list);
extern void vmw_compat_shaders_revert(struct vmw_compat_shader_manager *man,
				      struct list_head *list);
extern int vmw_compat_shader_remove(struct vmw_compat_shader_manager *man,
				    u32 user_key,
				    SVGA3dShaderType shader_type,
				    struct list_head *list);
extern int vmw_compat_shader_add(struct vmw_compat_shader_manager *man,
				 u32 user_key, const void *bytecode,
				 SVGA3dShaderType shader_type,
				 size_t size,
				 struct ttm_object_file *tfile,
				 struct list_head *list);
extern struct vmw_compat_shader_manager *
vmw_compat_shader_man_create(struct vmw_private *dev_priv);
extern void
vmw_compat_shader_man_destroy(struct vmw_compat_shader_manager *man);


/**
 * Inline helper functions
+168 −29
Original line number Diff line number Diff line
@@ -235,8 +235,12 @@ static void vmw_resource_relocations_apply(uint32_t *cb,
{
	struct vmw_resource_relocation *rel;

	list_for_each_entry(rel, list, head)
	list_for_each_entry(rel, list, head) {
		if (likely(rel->res != NULL))
			cb[rel->offset] = rel->res->id;
		else
			cb[rel->offset] = SVGA_3D_CMD_NOP;
	}
}

static int vmw_cmd_invalid(struct vmw_private *dev_priv,
@@ -381,21 +385,26 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)
}

/**
 * vmw_cmd_res_check - Check that a resource is present and if so, put it
 * vmw_cmd_compat_res_check - Check that a resource is present and if so, put it
 * on the resource validate list unless it's already there.
 *
 * @dev_priv: Pointer to a device private structure.
 * @sw_context: Pointer to the software context.
 * @res_type: Resource type.
 * @converter: User-space visisble type specific information.
 * @id: Pointer to the location in the command buffer currently being
 * @id: user-space resource id handle.
 * @id_loc: Pointer to the location in the command buffer currently being
 * parsed from where the user-space resource id handle is located.
 * @p_val: Pointer to pointer to resource validalidation node. Populated
 * on exit.
 */
static int vmw_cmd_res_check(struct vmw_private *dev_priv,
static int
vmw_cmd_compat_res_check(struct vmw_private *dev_priv,
			 struct vmw_sw_context *sw_context,
			 enum vmw_res_type res_type,
			 const struct vmw_user_resource_conv *converter,
			     uint32_t *id,
			 uint32_t id,
			 uint32_t *id_loc,
			 struct vmw_resource_val_node **p_val)
{
	struct vmw_res_cache_entry *rcache =
@@ -404,7 +413,7 @@ static int vmw_cmd_res_check(struct vmw_private *dev_priv,
	struct vmw_resource_val_node *node;
	int ret;

	if (*id == SVGA3D_INVALID_ID) {
	if (id == SVGA3D_INVALID_ID) {
		if (p_val)
			*p_val = NULL;
		if (res_type == vmw_res_context) {
@@ -419,7 +428,7 @@ static int vmw_cmd_res_check(struct vmw_private *dev_priv,
	 * resource
	 */

	if (likely(rcache->valid && *id == rcache->handle)) {
	if (likely(rcache->valid && id == rcache->handle)) {
		const struct vmw_resource *res = rcache->res;

		rcache->node->first_usage = false;
@@ -428,28 +437,28 @@ static int vmw_cmd_res_check(struct vmw_private *dev_priv,

		return vmw_resource_relocation_add
			(&sw_context->res_relocations, res,
			 id - sw_context->buf_start);
			 id_loc - sw_context->buf_start);
	}

	ret = vmw_user_resource_lookup_handle(dev_priv,
					      sw_context->tfile,
					      *id,
					      sw_context->fp->tfile,
					      id,
					      converter,
					      &res);
	if (unlikely(ret != 0)) {
		DRM_ERROR("Could not find or use resource 0x%08x.\n",
			  (unsigned) *id);
			  (unsigned) id);
		dump_stack();
		return ret;
	}

	rcache->valid = true;
	rcache->res = res;
	rcache->handle = *id;
	rcache->handle = id;

	ret = vmw_resource_relocation_add(&sw_context->res_relocations,
					  res,
					  id - sw_context->buf_start);
					  id_loc - sw_context->buf_start);
	if (unlikely(ret != 0))
		goto out_no_reloc;

@@ -482,6 +491,31 @@ out_no_reloc:
	return ret;
}

/**
 * vmw_cmd_res_check - Check that a resource is present and if so, put it
 * on the resource validate list unless it's already there.
 *
 * @dev_priv: Pointer to a device private structure.
 * @sw_context: Pointer to the software context.
 * @res_type: Resource type.
 * @converter: User-space visisble type specific information.
 * @id_loc: Pointer to the location in the command buffer currently being
 * parsed from where the user-space resource id handle is located.
 * @p_val: Pointer to pointer to resource validalidation node. Populated
 * on exit.
 */
static int
vmw_cmd_res_check(struct vmw_private *dev_priv,
		  struct vmw_sw_context *sw_context,
		  enum vmw_res_type res_type,
		  const struct vmw_user_resource_conv *converter,
		  uint32_t *id_loc,
		  struct vmw_resource_val_node **p_val)
{
	return vmw_cmd_compat_res_check(dev_priv, sw_context, res_type,
					converter, *id_loc, id_loc, p_val);
}

/**
 * vmw_cmd_cid_check - Check a command header for valid context information.
 *
@@ -769,7 +803,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
	struct vmw_relocation *reloc;
	int ret;

	ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
	if (unlikely(ret != 0)) {
		DRM_ERROR("Could not find or use MOB buffer.\n");
		return -EINVAL;
@@ -830,7 +864,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
	struct vmw_relocation *reloc;
	int ret;

	ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
	ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
	if (unlikely(ret != 0)) {
		DRM_ERROR("Could not find or use GMR region.\n");
		return -EINVAL;
@@ -1129,7 +1163,8 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,

	srf = vmw_res_to_srf(sw_context->res_cache[vmw_res_surface].res);

	vmw_kms_cursor_snoop(srf, sw_context->tfile, &vmw_bo->base, header);
	vmw_kms_cursor_snoop(srf, sw_context->fp->tfile, &vmw_bo->base,
			     header);

out_no_surface:
	vmw_dmabuf_unreference(&vmw_bo);
@@ -1480,6 +1515,98 @@ static int vmw_cmd_invalidate_gb_surface(struct vmw_private *dev_priv,
				 &cmd->body.sid, NULL);
}


/**
 * vmw_cmd_shader_define - Validate an SVGA_3D_CMD_SHADER_DEFINE
 * command
 *
 * @dev_priv: Pointer to a device private struct.
 * @sw_context: The software context being used for this batch.
 * @header: Pointer to the command header in the command stream.
 */
static int vmw_cmd_shader_define(struct vmw_private *dev_priv,
				 struct vmw_sw_context *sw_context,
				 SVGA3dCmdHeader *header)
{
	struct vmw_shader_define_cmd {
		SVGA3dCmdHeader header;
		SVGA3dCmdDefineShader body;
	} *cmd;
	int ret;
	size_t size;

	cmd = container_of(header, struct vmw_shader_define_cmd,
			   header);

	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
				user_context_converter, &cmd->body.cid,
				NULL);
	if (unlikely(ret != 0))
		return ret;

	if (unlikely(!dev_priv->has_mob))
		return 0;

	size = cmd->header.size - sizeof(cmd->body);
	ret = vmw_compat_shader_add(sw_context->fp->shman,
				    cmd->body.shid, cmd + 1,
				    cmd->body.type, size,
				    sw_context->fp->tfile,
				    &sw_context->staged_shaders);
	if (unlikely(ret != 0))
		return ret;

	return vmw_resource_relocation_add(&sw_context->res_relocations,
					   NULL, &cmd->header.id -
					   sw_context->buf_start);

	return 0;
}

/**
 * vmw_cmd_shader_destroy - Validate an SVGA_3D_CMD_SHADER_DESTROY
 * command
 *
 * @dev_priv: Pointer to a device private struct.
 * @sw_context: The software context being used for this batch.
 * @header: Pointer to the command header in the command stream.
 */
static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv,
				  struct vmw_sw_context *sw_context,
				  SVGA3dCmdHeader *header)
{
	struct vmw_shader_destroy_cmd {
		SVGA3dCmdHeader header;
		SVGA3dCmdDestroyShader body;
	} *cmd;
	int ret;

	cmd = container_of(header, struct vmw_shader_destroy_cmd,
			   header);

	ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
				user_context_converter, &cmd->body.cid,
				NULL);
	if (unlikely(ret != 0))
		return ret;

	if (unlikely(!dev_priv->has_mob))
		return 0;

	ret = vmw_compat_shader_remove(sw_context->fp->shman,
				       cmd->body.shid,
				       cmd->body.type,
				       &sw_context->staged_shaders);
	if (unlikely(ret != 0))
		return ret;

	return vmw_resource_relocation_add(&sw_context->res_relocations,
					   NULL, &cmd->header.id -
					   sw_context->buf_start);

	return 0;
}

/**
 * vmw_cmd_set_shader - Validate an SVGA_3D_CMD_SET_SHADER
 * command
@@ -1511,9 +1638,16 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
	if (dev_priv->has_mob) {
		struct vmw_ctx_bindinfo bi;
		struct vmw_resource_val_node *res_node;
		u32 shid = cmd->body.shid;

		(void) vmw_compat_shader_lookup(sw_context->fp->shman,
						cmd->body.type,
						&shid);

		ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_shader,
		ret = vmw_cmd_compat_res_check(dev_priv, sw_context,
					       vmw_res_shader,
					       user_shader_converter,
					       shid,
					       &cmd->body.shid, &res_node);
		if (unlikely(ret != 0))
			return ret;
@@ -1669,10 +1803,10 @@ static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
		    true, false, false),
	VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check,
		    false, false, false),
	VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check,
		    true, true, false),
	VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check,
		    true, true, false),
	VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_shader_define,
		    true, false, false),
	VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_shader_destroy,
		    true, false, false),
	VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader,
		    true, false, false),
	VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_set_shader_const,
@@ -2206,7 +2340,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
	} else
		sw_context->kernel = true;

	sw_context->tfile = vmw_fpriv(file_priv)->tfile;
	sw_context->fp = vmw_fpriv(file_priv);
	sw_context->cur_reloc = 0;
	sw_context->cur_val_buf = 0;
	sw_context->fence_flags = 0;
@@ -2223,6 +2357,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
			goto out_unlock;
		sw_context->res_ht_initialized = true;
	}
	INIT_LIST_HEAD(&sw_context->staged_shaders);

	INIT_LIST_HEAD(&resource_list);
	ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,
@@ -2311,6 +2446,8 @@ int vmw_execbuf_process(struct drm_file *file_priv,
	}

	list_splice_init(&sw_context->resource_list, &resource_list);
	vmw_compat_shaders_commit(sw_context->fp->shman,
				  &sw_context->staged_shaders);
	mutex_unlock(&dev_priv->cmdbuf_mutex);

	/*
@@ -2337,6 +2474,8 @@ out_unlock:
	list_splice_init(&sw_context->resource_list, &resource_list);
	error_resource = sw_context->error_resource;
	sw_context->error_resource = NULL;
	vmw_compat_shaders_revert(sw_context->fp->shman,
				  &sw_context->staged_shaders);
	mutex_unlock(&dev_priv->cmdbuf_mutex);

	/*
+417 −48

File changed.

Preview size limit exceeded, changes collapsed.