static void virtio_gpu_plane_atomic_update(struct drm_plane *plane,
					   struct drm_plane_state *old_state)
{
	struct drm_device *dev = plane->dev;
	struct virtio_gpu_device *vgdev = dev->dev_private;
	struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(plane->crtc);
	struct virtio_gpu_framebuffer *vgfb;
	struct virtio_gpu_object *bo;
	uint32_t handle;

	if (plane->fb) {
		vgfb = to_virtio_gpu_framebuffer(plane->fb);
		bo = gem_to_virtio_gpu_obj(vgfb->obj);
		handle = bo->hw_res_handle;
	} else {
		handle = 0;
	}

	DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d\n", handle,
		  plane->state->crtc_w, plane->state->crtc_h,
		  plane->state->crtc_x, plane->state->crtc_y);
	virtio_gpu_cmd_set_scanout(vgdev, output->index, handle,
				   plane->state->crtc_w,
				   plane->state->crtc_h,
				   plane->state->crtc_x,
				   plane->state->crtc_y);
}
Beispiel #2
0
static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
					    struct drm_plane_state *old_state)
{
	struct drm_device *dev = plane->dev;
	struct virtio_gpu_device *vgdev = dev->dev_private;
	struct virtio_gpu_output *output = NULL;
	struct virtio_gpu_framebuffer *vgfb;
	struct virtio_gpu_object *bo;
	uint32_t handle;

	if (plane->state->crtc)
		output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
	if (old_state->crtc)
		output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
	if (WARN_ON(!output))
		return;

	if (plane->state->fb && output->enabled) {
		vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
		bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
		handle = bo->hw_res_handle;
		if (bo->dumb) {
			virtio_gpu_cmd_transfer_to_host_2d
				(vgdev, bo, 0,
				 cpu_to_le32(plane->state->src_w >> 16),
				 cpu_to_le32(plane->state->src_h >> 16),
				 cpu_to_le32(plane->state->src_x >> 16),
				 cpu_to_le32(plane->state->src_y >> 16), NULL);
		}
Beispiel #3
0
void virtio_gpu_gem_free_object(struct drm_gem_object *gem_obj)
{
	struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(gem_obj);

	if (obj)
		virtio_gpu_object_unref(&obj);
}
Beispiel #4
0
int
virtio_gpu_framebuffer_init(struct drm_device *dev,
			    struct virtio_gpu_framebuffer *vgfb,
			    const struct drm_mode_fb_cmd2 *mode_cmd,
			    struct drm_gem_object *obj)
{
	int ret;
	struct virtio_gpu_object *bo;

	vgfb->base.obj[0] = obj;

	bo = gem_to_virtio_gpu_obj(obj);

	drm_helper_mode_fill_fb_struct(dev, &vgfb->base, mode_cmd);

	ret = drm_framebuffer_init(dev, &vgfb->base, &virtio_gpu_fb_funcs);
	if (ret) {
		vgfb->base.obj[0] = NULL;
		return ret;
	}

	spin_lock_init(&vgfb->dirty_lock);
	vgfb->x1 = vgfb->y1 = INT_MAX;
	vgfb->x2 = vgfb->y2 = 0;
	return 0;
}
static int virtio_gpu_crtc_cursor_set(struct drm_crtc *crtc,
				      struct drm_file *file_priv,
				      uint32_t handle,
				      uint32_t width,
				      uint32_t height,
				      int32_t hot_x, int32_t hot_y)
{
	struct virtio_gpu_device *vgdev = crtc->dev->dev_private;
	struct virtio_gpu_output *output =
		container_of(crtc, struct virtio_gpu_output, crtc);
	struct drm_gem_object *gobj = NULL;
	struct virtio_gpu_object *qobj = NULL;
	struct virtio_gpu_fence *fence = NULL;
	int ret = 0;

	if (handle == 0) {
		virtio_gpu_hide_cursor(vgdev, output);
		return 0;
	}

	/* lookup the cursor */
	gobj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
	if (gobj == NULL)
		return -ENOENT;

	qobj = gem_to_virtio_gpu_obj(gobj);

	if (!qobj->hw_res_handle) {
		ret = -EINVAL;
		goto out;
	}

	virtio_gpu_cmd_transfer_to_host_2d(vgdev, qobj->hw_res_handle, 0,
					   cpu_to_le32(64),
					   cpu_to_le32(64),
					   0, 0, &fence);
	ret = virtio_gpu_object_reserve(qobj, false);
	if (!ret) {
		reservation_object_add_excl_fence(qobj->tbo.resv,
						  &fence->f);
		fence_put(&fence->f);
		virtio_gpu_object_unreserve(qobj);
		virtio_gpu_object_wait(qobj, false);
	}

	output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
	output->cursor.resource_id = cpu_to_le32(qobj->hw_res_handle);
	output->cursor.hot_x = cpu_to_le32(hot_x);
	output->cursor.hot_y = cpu_to_le32(hot_y);
	virtio_gpu_cursor_ping(vgdev, output);
	ret = 0;

out:
	drm_gem_object_unreference_unlocked(gobj);
	return ret;
}
Beispiel #6
0
int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv,
			      struct drm_device *dev,
			      uint32_t handle, uint64_t *offset_p)
{
	struct drm_gem_object *gobj;
	struct virtio_gpu_object *obj;
	BUG_ON(!offset_p);
	gobj = drm_gem_object_lookup(file_priv, handle);
	if (gobj == NULL)
		return -ENOENT;
	obj = gem_to_virtio_gpu_obj(gobj);
	*offset_p = virtio_gpu_object_mmap_offset(obj);
	drm_gem_object_unreference_unlocked(gobj);
	return 0;
}
static int virtio_gpu_page_flip(struct drm_crtc *crtc,
				struct drm_framebuffer *fb,
				struct drm_pending_vblank_event *event,
				uint32_t flags)
{
	struct virtio_gpu_device *vgdev = crtc->dev->dev_private;
	struct virtio_gpu_output *output =
		container_of(crtc, struct virtio_gpu_output, crtc);
	struct drm_plane *plane = crtc->primary;
	struct virtio_gpu_framebuffer *vgfb;
	struct virtio_gpu_object *bo;
	unsigned long irqflags;
	uint32_t handle;

	plane->fb = fb;
	vgfb = to_virtio_gpu_framebuffer(plane->fb);
	bo = gem_to_virtio_gpu_obj(vgfb->obj);
	handle = bo->hw_res_handle;

	DRM_DEBUG("handle 0x%x%s, crtc %dx%d\n", handle,
		  bo->dumb ? ", dumb" : "",
		  crtc->mode.hdisplay, crtc->mode.vdisplay);
	if (bo->dumb) {
		virtio_gpu_cmd_transfer_to_host_2d
			(vgdev, handle, 0,
			 cpu_to_le32(crtc->mode.hdisplay),
			 cpu_to_le32(crtc->mode.vdisplay),
			 0, 0, NULL);
	}
	virtio_gpu_cmd_set_scanout(vgdev, output->index, handle,
				   crtc->mode.hdisplay,
				   crtc->mode.vdisplay, 0, 0);
	virtio_gpu_cmd_resource_flush(vgdev, handle, 0, 0,
				      crtc->mode.hdisplay,
				      crtc->mode.vdisplay);

	if (event) {
		spin_lock_irqsave(&crtc->dev->event_lock, irqflags);
		drm_send_vblank_event(crtc->dev, -1, event);
		spin_unlock_irqrestore(&crtc->dev->event_lock, irqflags);
	}

	return 0;
}
Beispiel #8
0
void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
				 struct drm_file *file)
{
	struct virtio_gpu_device *vgdev = obj->dev->dev_private;
	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
	struct virtio_gpu_object *qobj = gem_to_virtio_gpu_obj(obj);
	int r;

	if (!vgdev->has_virgl_3d)
		return;

	r = virtio_gpu_object_reserve(qobj, false);
	if (r)
		return;

	virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id,
						qobj->hw_res_handle);
	virtio_gpu_object_unreserve(qobj);
}
Beispiel #9
0
int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *vgfb,
			     struct drm_clip_rect *clips,
			     unsigned int num_clips)
{
	struct virtio_gpu_device *vgdev = vgfb->base.dev->dev_private;
	struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
	struct drm_clip_rect norect;
	struct drm_clip_rect *clips_ptr;
	int left, right, top, bottom;
	int i;
	int inc = 1;

	if (!num_clips) {
		num_clips = 1;
		clips = &norect;
		norect.x1 = norect.y1 = 0;
		norect.x2 = vgfb->base.width;
		norect.y2 = vgfb->base.height;
	}
	left = clips->x1;
	right = clips->x2;
	top = clips->y1;
	bottom = clips->y2;

	/* skip the first clip rect */
	for (i = 1, clips_ptr = clips + inc;
	     i < num_clips; i++, clips_ptr += inc) {
		left = min_t(int, left, (int)clips_ptr->x1);
		right = max_t(int, right, (int)clips_ptr->x2);
		top = min_t(int, top, (int)clips_ptr->y1);
		bottom = max_t(int, bottom, (int)clips_ptr->y2);
	}

	if (obj->dumb)
		return virtio_gpu_dirty_update(vgfb, false, left, top,
					       right - left, bottom - top);

	virtio_gpu_cmd_resource_flush(vgdev, obj->hw_res_handle,
				      left, top, right - left, bottom - top);
	return 0;
}
Beispiel #10
0
int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
				struct drm_device *dev,
				struct drm_mode_create_dumb *args)
{
	struct virtio_gpu_device *vgdev = dev->dev_private;
	struct drm_gem_object *gobj;
	struct virtio_gpu_object *obj;
	int ret;
	uint32_t pitch;
	uint32_t resid;
	uint32_t format;

	pitch = args->width * ((args->bpp + 1) / 8);
	args->size = pitch * args->height;
	args->size = ALIGN(args->size, PAGE_SIZE);

	ret = virtio_gpu_gem_create(file_priv, dev, args->size, &gobj,
				    &args->handle);
	if (ret)
		goto fail;

	format = virtio_gpu_translate_format(DRM_FORMAT_XRGB8888);
	virtio_gpu_resource_id_get(vgdev, &resid);
	virtio_gpu_cmd_create_resource(vgdev, resid, format,
				       args->width, args->height);

	/* attach the object to the resource */
	obj = gem_to_virtio_gpu_obj(gobj);
	ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL);
	if (ret)
		goto fail;

	obj->dumb = true;
	args->pitch = pitch;
	return ret;

fail:
	return ret;
}
Beispiel #11
0
static int virtio_gpu_dirty_update(struct virtio_gpu_framebuffer *fb,
				   bool store, int x, int y,
				   int width, int height)
{
	struct drm_device *dev = fb->base.dev;
	struct virtio_gpu_device *vgdev = dev->dev_private;
	bool store_for_later = false;
	int bpp = fb->base.format->cpp[0];
	int x2, y2;
	unsigned long flags;
	struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(fb->base.obj[0]);

	if ((width <= 0) ||
	    (x + width > fb->base.width) ||
	    (y + height > fb->base.height)) {
		DRM_DEBUG("values out of range %dx%d+%d+%d, fb %dx%d\n",
			  width, height, x, y,
			  fb->base.width, fb->base.height);
		return -EINVAL;
	}

	/*
	 * Can be called with pretty much any context (console output
	 * path).  If we are in atomic just store the dirty rect info
	 * to send out the update later.
	 *
	 * Can't test inside spin lock.
	 */
	if (in_atomic() || store)
		store_for_later = true;

	x2 = x + width - 1;
	y2 = y + height - 1;

	spin_lock_irqsave(&fb->dirty_lock, flags);

	if (fb->y1 < y)
		y = fb->y1;
	if (fb->y2 > y2)
		y2 = fb->y2;
	if (fb->x1 < x)
		x = fb->x1;
	if (fb->x2 > x2)
		x2 = fb->x2;

	if (store_for_later) {
		fb->x1 = x;
		fb->x2 = x2;
		fb->y1 = y;
		fb->y2 = y2;
		spin_unlock_irqrestore(&fb->dirty_lock, flags);
		return 0;
	}

	fb->x1 = fb->y1 = INT_MAX;
	fb->x2 = fb->y2 = 0;

	spin_unlock_irqrestore(&fb->dirty_lock, flags);

	{
		uint32_t offset;
		uint32_t w = x2 - x + 1;
		uint32_t h = y2 - y + 1;

		offset = (y * fb->base.pitches[0]) + x * bpp;

		virtio_gpu_cmd_transfer_to_host_2d(vgdev, obj->hw_res_handle,
						   offset,
						   cpu_to_le32(w),
						   cpu_to_le32(h),
						   cpu_to_le32(x),
						   cpu_to_le32(y),
						   NULL);

	}
	virtio_gpu_cmd_resource_flush(vgdev, obj->hw_res_handle,
				      x, y, x2 - x + 1, y2 - y + 1);
	return 0;
}