Commit 504901db authored by Deepak Rawat's avatar Deepak Rawat Committed by Roland Scheidegger
Browse files

drm/vmwgfx: Refactor surface_define to use vmw_surface_metadata



Makes surface_define cleaner by sending vmw_surface_metadata instead of
all the arguments individually.

v2: fix uninitialized return value, error message

Signed-off-by: default avatarDeepak Rawat <drawat.floss@gmail.com>
Reviewed-by: default avatarBrian Paul <brianp@vmware.com>
Reviewed-by: default avatarThomas Hellström (VMware) <thomas_os@shipmail.org>
Reviewed-by: default avatarRoland Scheidegger <sroland@vmware.com>
Signed-off-by: default avatarRoland Scheidegger <sroland@vmware.com>
parent 26b82873
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1309,6 +1309,11 @@ extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev,
					      void *data,
					      struct drm_file *file_priv);

int vmw_gb_surface_define(struct vmw_private *dev_priv,
			  uint32_t user_accounting_size,
			  const struct vmw_surface_metadata *req,
			  struct vmw_surface **srf_out);

/*
 * Shader management - vmwgfx_shader.c
 */
+10 −17
Original line number Diff line number Diff line
@@ -1144,8 +1144,8 @@ static int vmw_create_bo_proxy(struct drm_device *dev,
			       struct vmw_buffer_object *bo_mob,
			       struct vmw_surface **srf_out)
{
	struct vmw_surface_metadata metadata = {0};
	uint32_t format;
	struct drm_vmw_size content_base_size = {0};
	struct vmw_resource *res;
	unsigned int bytes_pp;
	struct drm_format_name_buf format_name;
@@ -1175,22 +1175,15 @@ static int vmw_create_bo_proxy(struct drm_device *dev,
		return -EINVAL;
	}

	content_base_size.width  = mode_cmd->pitches[0] / bytes_pp;
	content_base_size.height = mode_cmd->height;
	content_base_size.depth  = 1;

	ret = vmw_surface_gb_priv_define(dev,
					 0, /* kernel visible only */
					 0, /* flags */
					 format,
					 true, /* can be a scanout buffer */
					 1, /* num of mip levels */
					 0,
					 0,
					 content_base_size,
					 SVGA3D_MS_PATTERN_NONE,
					 SVGA3D_MS_QUALITY_NONE,
					 srf_out);
	metadata.format = format;
	metadata.mip_levels[0] = 1;
	metadata.num_sizes = 1;
	metadata.base_size.width = mode_cmd->pitches[0] / bytes_pp;
	metadata.base_size.height =  mode_cmd->height;
	metadata.base_size.depth = 1;
	metadata.scanout = true;

	ret = vmw_gb_surface_define(vmw_priv(dev), 0, &metadata, srf_out);
	if (ret) {
		DRM_ERROR("Failed to allocate proxy content buffer\n");
		return ret;
+16 −35
Original line number Diff line number Diff line
@@ -1041,7 +1041,6 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
	struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
	enum stdu_content_type new_content_type;
	struct vmw_framebuffer_surface *new_vfbs;
	struct drm_crtc *crtc = new_state->crtc;
	uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
	int ret;

@@ -1068,12 +1067,11 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
		new_content_type = SEPARATE_SURFACE;

	if (new_content_type != SAME_AS_DISPLAY) {
		struct vmw_surface content_srf;
		struct drm_vmw_size display_base_size = {0};
		struct vmw_surface_metadata metadata = {0};

		display_base_size.width  = hdisplay;
		display_base_size.height = vdisplay;
		display_base_size.depth  = 1;
		metadata.base_size.width = hdisplay;
		metadata.base_size.height = vdisplay;
		metadata.base_size.depth = 1;

		/*
		 * If content buffer is a buffer object, then we have to
@@ -1083,15 +1081,15 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,

			switch (new_fb->format->cpp[0]*8) {
			case 32:
				content_srf.metadata.format = SVGA3D_X8R8G8B8;
				metadata.format = SVGA3D_X8R8G8B8;
				break;

			case 16:
				content_srf.metadata.format = SVGA3D_R5G6B5;
				metadata.format = SVGA3D_R5G6B5;
				break;

			case 8:
				content_srf.metadata.format = SVGA3D_P8;
				metadata.format = SVGA3D_P8;
				break;

			default:
@@ -1099,25 +1097,20 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
				return -EINVAL;
			}

			content_srf.metadata.flags = 0;
			content_srf.metadata.mip_levels[0] = 1;
			content_srf.metadata.multisample_count = 0;
			content_srf.metadata.multisample_pattern =
				SVGA3D_MS_PATTERN_NONE;
			content_srf.metadata.quality_level =
				SVGA3D_MS_QUALITY_NONE;
			metadata.mip_levels[0] = 1;
			metadata.num_sizes = 1;
			metadata.scanout = true;
		} else {
			content_srf = *new_vfbs->surface;
			metadata = new_vfbs->surface->metadata;
		}

		if (vps->surf) {
			struct drm_vmw_size cur_base_size =
				vps->surf->metadata.base_size;

			if (cur_base_size.width != display_base_size.width ||
			    cur_base_size.height != display_base_size.height ||
			    vps->surf->metadata.format !=
			    content_srf.metadata.format) {
			if (cur_base_size.width != metadata.base_size.width ||
			    cur_base_size.height != metadata.base_size.height ||
			    vps->surf->metadata.format != metadata.format) {
				WARN_ON(vps->pinned != 0);
				vmw_surface_unreference(&vps->surf);
			}
@@ -1125,19 +1118,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
		}

		if (!vps->surf) {
			ret = vmw_surface_gb_priv_define
				(crtc->dev,
				 /* Kernel visible only */
				 0,
				 content_srf.metadata.flags,
				 content_srf.metadata.format,
				 true,  /* a scanout buffer */
				 content_srf.metadata.mip_levels[0],
				 content_srf.metadata.multisample_count,
				 0,
				 display_base_size,
				 content_srf.metadata.multisample_pattern,
				 content_srf.metadata.quality_level,
			ret = vmw_gb_surface_define(dev_priv, 0, &metadata,
						    &vps->surf);
			if (ret != 0) {
				DRM_ERROR("Couldn't allocate STDU surface.\n");
+184 −194
Original line number Diff line number Diff line
@@ -1320,7 +1320,6 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res)
	return 0;
}


/**
 * vmw_gb_surface_define_ioctl - Ioctl function implementing
 * the user surface define functionality.
@@ -1376,173 +1375,6 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
	return ret;
}

/**
 * vmw_surface_gb_priv_define - Define a private GB surface
 *
 * @dev:  Pointer to a struct drm_device
 * @user_accounting_size:  Used to track user-space memory usage, set
 *                         to 0 for kernel mode only memory
 * @svga3d_flags: SVGA3d surface flags for the device
 * @format: requested surface format
 * @for_scanout: true if inteded to be used for scanout buffer
 * @num_mip_levels:  number of MIP levels
 * @multisample_count:
 * @array_size: Surface array size.
 * @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.
 *
 * GB surfaces allocated by this function will not have a user mode handle, and
 * thus will only be visible to vmwgfx.  For optimization reasons the
 * surface may later be given a user mode handle by another function to make
 * it available to user mode drivers.
 */
int vmw_surface_gb_priv_define(struct drm_device *dev,
			       uint32_t user_accounting_size,
			       SVGA3dSurfaceAllFlags svga3d_flags,
			       SVGA3dSurfaceFormat format,
			       bool for_scanout,
			       uint32_t num_mip_levels,
			       uint32_t multisample_count,
			       uint32_t array_size,
			       struct drm_vmw_size size,
			       SVGA3dMSPattern multisample_pattern,
			       SVGA3dMSQualityLevel quality_level,
			       struct vmw_surface **srf_out)
{
	struct vmw_private *dev_priv = vmw_priv(dev);
	struct vmw_user_surface *user_srf;
	struct ttm_operation_ctx ctx = {
		.interruptible = true,
		.no_wait_gpu = false
	};
	struct vmw_surface *srf;
	struct vmw_surface_metadata *metadata;
	int ret;
	u32 num_layers = 1;
	u32 sample_count = 1;

	*srf_out = NULL;

	if (for_scanout) {
		if (!svga3dsurface_is_screen_target_format(format)) {
			VMW_DEBUG_USER("Invalid Screen Target surface format.");
			return -EINVAL;
		}

		if (size.width > dev_priv->texture_max_width ||
		    size.height > dev_priv->texture_max_height) {
			VMW_DEBUG_USER("%ux%u\n, exceeds max surface size %ux%u",
				       size.width, size.height,
				       dev_priv->texture_max_width,
				       dev_priv->texture_max_height);
			return -EINVAL;
		}
	} else {
		const struct svga3d_surface_desc *desc;

		desc = svga3dsurface_get_desc(format);
		if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {
			VMW_DEBUG_USER("Invalid surface format.\n");
			return -EINVAL;
		}
	}

	/* array_size must be null for non-GL3 host. */
	if (array_size > 0 && !has_sm4_context(dev_priv)) {
		VMW_DEBUG_USER("Tried to create DX surface on non-DX host.\n");
		return -EINVAL;
	}

	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
				   user_accounting_size, &ctx);
	if (unlikely(ret != 0)) {
		if (ret != -ERESTARTSYS)
			DRM_ERROR("Out of graphics memory for surface"
				  " creation.\n");
		goto out_unlock;
	}

	user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
	if (unlikely(!user_srf)) {
		ret = -ENOMEM;
		goto out_no_user_srf;
	}

	*srf_out  = &user_srf->srf;
	user_srf->size = user_accounting_size;
	user_srf->prime.base.shareable = false;
	user_srf->prime.base.tfile     = NULL;

	srf = &user_srf->srf;
	metadata = &srf->metadata;
	metadata->flags = svga3d_flags;
	metadata->format = format;
	metadata->scanout = for_scanout;
	metadata->mip_levels[0] = num_mip_levels;
	metadata->num_sizes = 1;
	metadata->sizes = NULL;
	srf->offsets = NULL;
	metadata->base_size = size;
	metadata->autogen_filter = SVGA3D_TEX_FILTER_NONE;
	metadata->array_size = array_size;
	metadata->multisample_count = multisample_count;
	metadata->multisample_pattern = multisample_pattern;
	metadata->quality_level = quality_level;

	if (array_size)
		num_layers = array_size;
	else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP)
		num_layers = SVGA3D_MAX_SURFACE_FACES;

	if (metadata->flags & SVGA3D_SURFACE_MULTISAMPLE)
		sample_count = metadata->multisample_count;

	srf->res.backup_size =
		svga3dsurface_get_serialized_size_extended(metadata->format,
							   metadata->base_size,
							   metadata->mip_levels[0],
							   num_layers,
							   sample_count);

	if (metadata->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
		srf->res.backup_size += sizeof(SVGA3dDXSOState);

	/*
	 * Don't set SVGA3D_SURFACE_SCREENTARGET flag for a scanout surface with
	 * size greater than STDU max width/height. This is really a workaround
	 * to support creation of big framebuffer requested by some user-space
	 * for whole topology. That big framebuffer won't really be used for
	 * binding with screen target as during prepare_fb a separate surface is
	 * created so it's safe to ignore SVGA3D_SURFACE_SCREENTARGET flag.
	 */
	if (dev_priv->active_display_unit == vmw_du_screen_target &&
	    for_scanout && size.width <= dev_priv->stdu_max_width &&
	    size.height <= dev_priv->stdu_max_height)
		metadata->flags |= SVGA3D_SURFACE_SCREENTARGET;

	/*
	 * From this point, the generic resource management functions
	 * destroy the object on failure.
	 */
	ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);

	ttm_read_unlock(&dev_priv->reservation_sem);
	return ret;

out_no_user_srf:
	ttm_mem_global_free(vmw_mem_glob(dev_priv), user_accounting_size);

out_unlock:
	ttm_read_unlock(&dev_priv->reservation_sem);
	return ret;
}

/**
 * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing
 * the user surface define functionality.
@@ -1596,43 +1428,55 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
			       struct drm_vmw_gb_surface_create_rep *rep,
			       struct drm_file *file_priv)
{
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
	struct vmw_private *dev_priv = vmw_priv(dev);
	struct vmw_user_surface *user_srf;
	struct vmw_surface_metadata metadata = {0};
	struct vmw_surface *srf;
	struct vmw_resource *res;
	struct vmw_resource *tmp;
	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
	int ret;
	int ret = 0;
	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);

	/* array_size must be null for non-GL3 host. */
	if (req->base.array_size > 0 && !has_sm4_context(dev_priv)) {
		VMW_DEBUG_USER("SM4 surface not supported.\n");
		return -EINVAL;
	}

	if (!has_sm4_1_context(dev_priv)) {
		/*
		 * If SM4_1 is not support then cannot send 64-bit flag to
		 * device.
		 */
		if (req->svga3d_flags_upper_32_bits != 0)
			return -EINVAL;
			ret = -EINVAL;

		if (req->base.multisample_count != 0)
			return -EINVAL;
			ret = -EINVAL;

		if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE)
			return -EINVAL;
			ret = -EINVAL;

		if (req->quality_level != SVGA3D_MS_QUALITY_NONE)
			return -EINVAL;
			ret = -EINVAL;

		if (ret) {
			VMW_DEBUG_USER("SM4.1 surface not supported.\n");
			return ret;
		}
	}

	if ((svga3d_flags_64 & SVGA3D_SURFACE_MULTISAMPLE) &&
	    req->base.multisample_count == 0)
	    req->base.multisample_count == 0) {
		VMW_DEBUG_USER("Invalid sample count.\n");
		return -EINVAL;
	}

	if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS)
	if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) {
		VMW_DEBUG_USER("Invalid mip level.\n");
		return -EINVAL;
	}

	if (unlikely(vmw_user_surface_size == 0))
		vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
@@ -1640,22 +1484,24 @@ vmw_gb_surface_define_internal(struct drm_device *dev,

	size = vmw_user_surface_size;

	metadata.flags = svga3d_flags_64;
	metadata.format = req->base.format;
	metadata.mip_levels[0] = req->base.mip_levels;
	metadata.multisample_count = req->base.multisample_count;
	metadata.multisample_pattern = req->multisample_pattern;
	metadata.quality_level = req->quality_level;
	metadata.array_size = req->base.array_size;
	metadata.num_sizes = 1;
	metadata.base_size = req->base.base_size;
	metadata.scanout = req->base.drm_surface_flags &
		drm_vmw_surface_flag_scanout;

	/* 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))
	ret = vmw_gb_surface_define(dev_priv, size, &metadata, &srf);
	if (ret != 0) {
		VMW_DEBUG_USER("Failed to define surface.\n");
		return ret;
	}

	user_srf = container_of(srf, struct vmw_user_surface, srf);
	if (drm_is_primary_client(file_priv))
@@ -2165,3 +2011,147 @@ static int vmw_surface_clean(struct vmw_resource *res)

	return 0;
}

/*
 * vmw_gb_surface_define - Define a private GB surface
 *
 * @dev_priv: Pointer to a device private.
 * @user_accounting_size:  Used to track user-space memory usage, set
 *                         to 0 for kernel mode only memory
 * @metadata: Metadata representing the surface to create.
 * @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
 * thus will only be visible to vmwgfx.  For optimization reasons the
 * surface may later be given a user mode handle by another function to make
 * it available to user mode drivers.
 */
int vmw_gb_surface_define(struct vmw_private *dev_priv,
			  uint32_t user_accounting_size,
			  const struct vmw_surface_metadata *req,
			  struct vmw_surface **srf_out)
{
	struct vmw_surface_metadata *metadata;
	struct vmw_user_surface *user_srf;
	struct vmw_surface *srf;
	struct ttm_operation_ctx ctx = {
		.interruptible = true,
		.no_wait_gpu = false
	};
	u32 sample_count = 1;
	u32 num_layers = 1;
	int ret;

	*srf_out = NULL;

	if (req->scanout) {
		if (!svga3dsurface_is_screen_target_format(req->format)) {
			VMW_DEBUG_USER("Invalid Screen Target surface format.");
			return -EINVAL;
		}

		if (req->base_size.width > dev_priv->texture_max_width ||
		    req->base_size.height > dev_priv->texture_max_height) {
			VMW_DEBUG_USER("%ux%u\n, exceed max surface size %ux%u",
				       req->base_size.width,
				       req->base_size.height,
				       dev_priv->texture_max_width,
				       dev_priv->texture_max_height);
			return -EINVAL;
		}
	} else {
		const struct svga3d_surface_desc *desc =
			svga3dsurface_get_desc(req->format);

		if (desc->block_desc == SVGA3DBLOCKDESC_NONE) {
			VMW_DEBUG_USER("Invalid surface format.\n");
			return -EINVAL;
		}
	}

	if (req->autogen_filter != SVGA3D_TEX_FILTER_NONE)
		return -EINVAL;

	if (req->num_sizes != 1)
		return -EINVAL;

	if (req->sizes != NULL)
		return -EINVAL;

	ret = ttm_read_lock(&dev_priv->reservation_sem, true);
	if (unlikely(ret != 0))
		return ret;

	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
				   user_accounting_size, &ctx);
	if (ret != 0) {
		if (ret != -ERESTARTSYS)
			DRM_ERROR("Out of graphics memory for surface.\n");
		goto out_unlock;
	}

	user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
	if (unlikely(!user_srf)) {
		ret = -ENOMEM;
		goto out_no_user_srf;
	}

	*srf_out  = &user_srf->srf;
	user_srf->size = user_accounting_size;
	user_srf->prime.base.shareable = false;
	user_srf->prime.base.tfile = NULL;

	srf = &user_srf->srf;
	srf->metadata = *req;
	srf->offsets = NULL;

	metadata = &srf->metadata;

	if (metadata->array_size)
		num_layers = req->array_size;
	else if (metadata->flags & SVGA3D_SURFACE_CUBEMAP)
		num_layers = SVGA3D_MAX_SURFACE_FACES;

	if (metadata->flags & SVGA3D_SURFACE_MULTISAMPLE)
		sample_count = metadata->multisample_count;

	srf->res.backup_size =
		svga3dsurface_get_serialized_size_extended(metadata->format,
							   metadata->base_size,
							   metadata->mip_levels[0],
							   num_layers,
							   sample_count);

	if (metadata->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
		srf->res.backup_size += sizeof(SVGA3dDXSOState);

	/*
	 * Don't set SVGA3D_SURFACE_SCREENTARGET flag for a scanout surface with
	 * size greater than STDU max width/height. This is really a workaround
	 * to support creation of big framebuffer requested by some user-space
	 * for whole topology. That big framebuffer won't really be used for
	 * binding with screen target as during prepare_fb a separate surface is
	 * created so it's safe to ignore SVGA3D_SURFACE_SCREENTARGET flag.
	 */
	if (dev_priv->active_display_unit == vmw_du_screen_target &&
	    metadata->scanout &&
	    metadata->base_size.width <= dev_priv->stdu_max_width &&
	    metadata->base_size.height <= dev_priv->stdu_max_height)
		metadata->flags |= SVGA3D_SURFACE_SCREENTARGET;

	/*
	 * From this point, the generic resource management functions
	 * destroy the object on failure.
	 */
	ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);

	ttm_read_unlock(&dev_priv->reservation_sem);
	return ret;

out_no_user_srf:
	ttm_mem_global_free(vmw_mem_glob(dev_priv), user_accounting_size);

out_unlock:
	ttm_read_unlock(&dev_priv->reservation_sem);
	return ret;
}