vkms_plane.c 5.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// SPDX-License-Identifier: GPL-2.0
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include "vkms_drv.h"
#include <drm/drm_plane_helper.h>
11
#include <drm/drm_atomic.h>
12
#include <drm/drm_atomic_helper.h>
13
#include <drm/drm_gem_framebuffer_helper.h>
14

H
Haneen Mohammed 已提交
15 16 17 18
static struct drm_plane_state *
vkms_plane_duplicate_state(struct drm_plane *plane)
{
	struct vkms_plane_state *vkms_state;
19
	struct vkms_crc_data *crc_data;
H
Haneen Mohammed 已提交
20 21 22 23 24

	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
	if (!vkms_state)
		return NULL;

25 26 27 28 29 30
	crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL);
	if (WARN_ON(!crc_data))
		DRM_INFO("Couldn't allocate crc_data");

	vkms_state->crc_data = crc_data;

H
Haneen Mohammed 已提交
31 32 33 34 35 36 37 38 39 40
	__drm_atomic_helper_plane_duplicate_state(plane,
						  &vkms_state->base);

	return &vkms_state->base;
}

static void vkms_plane_destroy_state(struct drm_plane *plane,
				     struct drm_plane_state *old_state)
{
	struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
41 42 43 44 45 46 47 48 49 50 51 52
	struct drm_crtc *crtc = vkms_state->base.crtc;

	if (crtc) {
		/* dropping the reference we acquired in
		 * vkms_primary_plane_update()
		 */
		if (drm_framebuffer_read_refcount(&vkms_state->crc_data->fb))
			drm_framebuffer_put(&vkms_state->crc_data->fb);
	}

	kfree(vkms_state->crc_data);
	vkms_state->crc_data = NULL;
H
Haneen Mohammed 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

	__drm_atomic_helper_plane_destroy_state(old_state);
	kfree(vkms_state);
}

static void vkms_plane_reset(struct drm_plane *plane)
{
	struct vkms_plane_state *vkms_state;

	if (plane->state)
		vkms_plane_destroy_state(plane, plane->state);

	vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
	if (!vkms_state) {
		DRM_ERROR("Cannot allocate vkms_plane_state\n");
		return;
	}

	plane->state = &vkms_state->base;
	plane->state->plane = plane;
}

75 76 77 78
static const struct drm_plane_funcs vkms_plane_funcs = {
	.update_plane		= drm_atomic_helper_update_plane,
	.disable_plane		= drm_atomic_helper_disable_plane,
	.destroy		= drm_plane_cleanup,
H
Haneen Mohammed 已提交
79 80 81
	.reset			= vkms_plane_reset,
	.atomic_duplicate_state = vkms_plane_duplicate_state,
	.atomic_destroy_state	= vkms_plane_destroy_state,
82 83
};

84 85
static void vkms_plane_atomic_update(struct drm_plane *plane,
				     struct drm_plane_state *old_state)
86
{
87
	struct vkms_plane_state *vkms_plane_state;
88
	struct drm_framebuffer *fb = plane->state->fb;
89 90
	struct vkms_crc_data *crc_data;

91
	if (!plane->state->crtc || !fb)
92 93 94
		return;

	vkms_plane_state = to_vkms_plane_state(plane->state);
95

96 97
	crc_data = vkms_plane_state->crc_data;
	memcpy(&crc_data->src, &plane->state->src, sizeof(struct drm_rect));
98 99
	memcpy(&crc_data->dst, &plane->state->dst, sizeof(struct drm_rect));
	memcpy(&crc_data->fb, fb, sizeof(struct drm_framebuffer));
100
	drm_framebuffer_get(&crc_data->fb);
101 102 103
	crc_data->offset = fb->offsets[0];
	crc_data->pitch = fb->pitches[0];
	crc_data->cpp = fb->format->cpp[0];
104 105
}

106 107 108 109
static int vkms_plane_atomic_check(struct drm_plane *plane,
				   struct drm_plane_state *state)
{
	struct drm_crtc_state *crtc_state;
110
	bool can_position = false;
111 112 113 114 115 116 117 118 119
	int ret;

	if (!state->fb | !state->crtc)
		return 0;

	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
	if (IS_ERR(crtc_state))
		return PTR_ERR(crtc_state);

120 121 122
	if (plane->type == DRM_PLANE_TYPE_CURSOR)
		can_position = true;

123 124 125
	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
						  DRM_PLANE_HELPER_NO_SCALING,
						  DRM_PLANE_HELPER_NO_SCALING,
126
						  can_position, true);
127 128 129 130
	if (ret != 0)
		return ret;

	/* for now primary plane must be visible and full screen */
131
	if (!state->visible && !can_position)
132 133 134 135 136
		return -EINVAL;

	return 0;
}

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static int vkms_prepare_fb(struct drm_plane *plane,
			   struct drm_plane_state *state)
{
	struct drm_gem_object *gem_obj;
	struct vkms_gem_object *vkms_obj;
	int ret;

	if (!state->fb)
		return 0;

	gem_obj = drm_gem_fb_get_obj(state->fb, 0);
	vkms_obj = drm_gem_to_vkms_gem(gem_obj);
	ret = vkms_gem_vmap(gem_obj);
	if (ret)
		DRM_ERROR("vmap failed: %d\n", ret);

	return drm_gem_fb_prepare_fb(plane, state);
}

static void vkms_cleanup_fb(struct drm_plane *plane,
			    struct drm_plane_state *old_state)
{
	struct drm_gem_object *gem_obj;

	if (!old_state->fb)
		return;

	gem_obj = drm_gem_fb_get_obj(old_state->fb, 0);
	vkms_gem_vunmap(gem_obj);
}

168
static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
169
	.atomic_update		= vkms_plane_atomic_update,
170
	.atomic_check		= vkms_plane_atomic_check,
171 172
	.prepare_fb		= vkms_prepare_fb,
	.cleanup_fb		= vkms_cleanup_fb,
173 174
};

175 176
struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev,
				  enum drm_plane_type type)
177 178
{
	struct drm_device *dev = &vkmsdev->drm;
179
	const struct drm_plane_helper_funcs *funcs;
180 181 182 183 184 185 186 187
	struct drm_plane *plane;
	const u32 *formats;
	int ret, nformats;

	plane = kzalloc(sizeof(*plane), GFP_KERNEL);
	if (!plane)
		return ERR_PTR(-ENOMEM);

188 189 190 191 192 193 194 195 196
	if (type == DRM_PLANE_TYPE_CURSOR) {
		formats = vkms_cursor_formats;
		nformats = ARRAY_SIZE(vkms_cursor_formats);
		funcs = &vkms_primary_helper_funcs;
	} else {
		formats = vkms_formats;
		nformats = ARRAY_SIZE(vkms_formats);
		funcs = &vkms_primary_helper_funcs;
	}
197 198 199 200

	ret = drm_universal_plane_init(dev, plane, 0,
				       &vkms_plane_funcs,
				       formats, nformats,
201
				       NULL, type, NULL);
202 203 204 205 206
	if (ret) {
		kfree(plane);
		return ERR_PTR(ret);
	}

207
	drm_plane_helper_add(plane, funcs);
208

209 210
	return plane;
}