Skip to content
Snippets Groups Projects
vmwgfx_stdu.c 39.2 KiB
Newer Older
/******************************************************************************
 *
 * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA
 * 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
 * THE COPYRIGHT HOLDERS, AUTHORS 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.
 *
 ******************************************************************************/

#include "vmwgfx_kms.h"
#include "svga3d_surfacedefs.h"
#include <drm/drm_plane_helper.h>

#define vmw_crtc_to_stdu(x) \
	container_of(x, struct vmw_screen_target_display_unit, base.crtc)
#define vmw_encoder_to_stdu(x) \
	container_of(x, struct vmw_screen_target_display_unit, base.encoder)
#define vmw_connector_to_stdu(x) \
	container_of(x, struct vmw_screen_target_display_unit, base.connector)



enum stdu_content_type {
	SAME_AS_DISPLAY = 0,
	SEPARATE_SURFACE,
	SEPARATE_DMA
};



/**
 * struct vmw_screen_target_display_unit
 *
 * @base: VMW specific DU structure
 * @display_srf: surface to be displayed.  The dimension of this will always
 *               match the display mode.  If the display mode matches
 *               content_vfbs dimensions, then this is a pointer into the
 *               corresponding field in content_vfbs.  If not, then this
 *               is a separate buffer to which content_vfbs will blit to.
 * @content_fb: holds the rendered content, can be a surface or DMA buffer
 * @content_type:  content_fb type
 * @defined:  true if the current display unit has been initialized
 */
struct vmw_screen_target_display_unit {
	struct vmw_display_unit base;

	struct vmw_surface     *display_srf;
	struct drm_framebuffer *content_fb;

	enum stdu_content_type content_fb_type;

	bool defined;
};



static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu);



/******************************************************************************
 * Screen Target Display Unit helper Functions
 *****************************************************************************/

/**
 * vmw_stdu_pin_display - pins the resource associated with the display surface
 *
 * @stdu: contains the display surface
 *
 * Since the display surface can either be a private surface allocated by us,
 * or it can point to the content surface, we use this function to not pin the
 * same resource twice.
 */
static int vmw_stdu_pin_display(struct vmw_screen_target_display_unit *stdu)
{
	return vmw_resource_pin(&stdu->display_srf->res, false);
}



/**
 * vmw_stdu_unpin_display - unpins the resource associated with display surface
 *
 * @stdu: contains the display surface
 *
 * If the display surface was privatedly allocated by
 * vmw_surface_gb_priv_define() and not registered as a framebuffer, then it
 * won't be automatically cleaned up when all the framebuffers are freed.  As
 * such, we have to explicitly call vmw_resource_unreference() to get it freed.
 */
static void vmw_stdu_unpin_display(struct vmw_screen_target_display_unit *stdu)
{
	if (stdu->display_srf) {
		struct vmw_resource *res = &stdu->display_srf->res;

		vmw_resource_unpin(res);

		if (stdu->content_fb_type != SAME_AS_DISPLAY) {
			vmw_resource_unreference(&res);
			stdu->content_fb_type = SAME_AS_DISPLAY;
		}

		stdu->display_srf = NULL;
	}
}



/******************************************************************************
 * Screen Target Display Unit CRTC Functions
 *****************************************************************************/


/**
 * vmw_stdu_crtc_destroy - cleans up the STDU
 *
 * @crtc: used to get a reference to the containing STDU
 */
static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc)
{
	vmw_stdu_destroy(vmw_crtc_to_stdu(crtc));
}



/**
 * vmw_stdu_dma_update - Update DMA buf dirty region on the SVGA device
 *
 * @dev_priv:  VMW DRM device
 * @file_priv: Pointer to a drm file private structure
 * @vfbs: VMW framebuffer surface that may need a DMA buf update
 * @x: top/left corner of the content area to blit from
 * @y: top/left corner of the content area to blit from
 * @width: width of the blit area
 * @height: height of the blit area
 *
 * The SVGA device may have the DMA buf cached, so before letting the
 * device use it as the source image for a subsequent operation, we
 * update the cached copy.
 *
 * RETURNs:
 * 0 on success, error code on failure
 */
static int vmw_stdu_dma_update(struct vmw_private *dev_priv,
			       struct drm_file *file_priv,
			       struct vmw_framebuffer_surface *vfbs,
			       uint32_t x, uint32_t y,
			       uint32_t width, uint32_t height)
{
	size_t fifo_size;
	struct {
		SVGA3dCmdHeader header;
		SVGA3dCmdUpdateGBImage body;
	} img_update_cmd;


	/* Only need to do this if the surface is a DMA buf proxy */
	if (!vfbs->is_dmabuf_proxy)
		return 0;

	fifo_size = sizeof(img_update_cmd);

	memset(&img_update_cmd, 0, fifo_size);
	img_update_cmd.header.id   = SVGA_3D_CMD_UPDATE_GB_IMAGE;
	img_update_cmd.header.size = sizeof(img_update_cmd.body);

	img_update_cmd.body.image.sid = vfbs->surface->res.id;

	img_update_cmd.body.box.x = x;
	img_update_cmd.body.box.y = y;
	img_update_cmd.body.box.w = width;
	img_update_cmd.body.box.h = height;
	img_update_cmd.body.box.d = 1;

	return vmw_execbuf_process(file_priv, dev_priv, NULL,
				   (void *) &img_update_cmd,
				   fifo_size, 0, VMW_QUIRK_SRC_SID_OK,
				   NULL, NULL);
}



Loading
Loading full blame...