[RFC 3/3] drm/vkms: Implement CRC debugfs API

Haneen Mohammed hamohammed.sa at gmail.com
Wed Jun 27 21:24:35 UTC 2018


Implement the .set_crc_source() callback.
Compute CRC using crc32 on the visible part of the framebuffer.
Use work_struct to compute and add CRC at the end of a vblank.

Signed-off-by: Haneen Mohammed <hamohammed.sa at gmail.com>
---
 drivers/gpu/drm/vkms/vkms_crtc.c | 76 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_drv.h  | 16 +++++++
 2 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 73aae129c37d..d78934b76e33 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -7,8 +7,78 @@
  */
 
 #include "vkms_drv.h"
+#include <linux/crc32.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+uint32_t _vkms_get_crc(struct drm_framebuffer *fb)
+{
+	struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
+	struct vkms_gem_object *vkms_obj = container_of(gem_obj,
+							struct vkms_gem_object,
+							gem);
+	u32 crc = 0;
+	int i = 0;
+	struct drm_plane_state *state = vkms_obj->plane_state;
+	unsigned int x = state->src.x1 >> 16;
+	unsigned int y = state->src.y1 >> 16;
+	unsigned int height = drm_rect_height(&state->src) >> 16;
+	unsigned int width = drm_rect_width(&state->src) >> 16;
+	unsigned int cpp = fb->format->cpp[0];
+	unsigned int src_offset;
+	unsigned int size_byte = width * cpp;
+	void *vaddr = vkms_obj->vaddr;
+
+	if (WARN_ON(!vaddr))
+		return crc;
+
+	for (i = y; i < y + height; i++) {
+		src_offset = fb->offsets[0] + (i * fb->pitches[0]) + (x * cpp);
+		crc = crc32_le(crc, vaddr + src_offset, size_byte);
+	}
+
+	return crc;
+}
+
+void vkms_crc_work_handle(struct work_struct *work)
+{
+	struct vkms_crtc_state *crtc_state = container_of(work,
+					     struct vkms_crtc_state,
+					     crc_workq);
+	struct drm_crtc *crtc = crtc_state->crtc;
+	struct drm_framebuffer *fb = (crtc->primary ? crtc->primary->fb : NULL);
+
+	if (crtc_state->crc_enabled && fb) {
+		u32 crc32 = _vkms_get_crc(fb);
+		unsigned int n_frame = drm_crtc_accurate_vblank_count(crtc);
+
+		drm_crtc_add_crc_entry(crtc, true, n_frame, &crc32);
+	}
+}
+
+static int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name,
+			       size_t *values_cnt)
+{
+	struct drm_device *dev = crtc->dev;
+	struct vkms_device *vkms_dev = container_of(dev,
+						    struct vkms_device,
+						    drm);
+	struct vkms_crtc_state *crtc_state = &vkms_dev->output.crtc_state;
+
+	if (!src_name) {
+		crtc_state->crc_enabled = false;
+	} else if (strcmp(src_name, "auto") == 0) {
+		crtc_state->crc_enabled = true;
+	} else {
+		crtc_state->crc_enabled = false;
+		return -EINVAL;
+	}
+
+	*values_cnt = 1;
+
+	return 0;
+}
 
 static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
 {
@@ -23,6 +93,8 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
 	if (!ret)
 		DRM_ERROR("vkms failure on handling vblank");
 
+	vkms_crc_work_handle(&output->crtc_state.crc_workq);
+
 	spin_lock_irqsave(&crtc->dev->event_lock, flags);
 	if (output->event) {
 		drm_crtc_send_vblank_event(crtc, output->event);
@@ -46,6 +118,9 @@ static int vkms_enable_vblank(struct drm_crtc *crtc)
 	out->period_ns = ktime_set(0, DEFAULT_VBLANK_NS);
 	hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_ABS);
 
+	out->crtc_state.crtc = crtc;
+	INIT_WORK(&out->crtc_state.crc_workq, vkms_crc_work_handle);
+
 	return 0;
 }
 
@@ -65,6 +140,7 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = {
 	.atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
 	.enable_vblank		= vkms_enable_vblank,
 	.disable_vblank		= vkms_disable_vblank,
+	.set_crc_source		= vkms_set_crc_source,
 };
 
 static int vkms_crtc_atomic_check(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 300e6a05d473..4a1458731dd7 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -22,6 +22,18 @@ static const u32 vkms_formats[] = {
 	DRM_FORMAT_XRGB8888,
 };
 
+/**
+ * struct vkms_crtc_state
+ * @crtc: backpointer to the CRTC
+ * @crc_workq: worker that captures CRCs for each frame
+ * @crc_enabled: flag to test if crc is enabled
+ */
+struct vkms_crtc_state {
+	struct drm_crtc *crtc;
+	struct work_struct crc_workq;
+	bool crc_enabled;
+};
+
 struct vkms_output {
 	struct drm_crtc crtc;
 	struct drm_encoder encoder;
@@ -29,6 +41,7 @@ struct vkms_output {
 	struct hrtimer vblank_hrtimer;
 	ktime_t period_ns;
 	struct drm_pending_vblank_event *event;
+	struct vkms_crtc_state crtc_state;
 };
 
 struct vkms_device {
@@ -55,6 +68,9 @@ int vkms_output_init(struct vkms_device *vkmsdev);
 
 struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev);
 
+/* CRC Support */
+void vkms_crc_work_handle(struct work_struct *work);
+
 /* Gem stuff */
 struct drm_gem_object *vkms_gem_create(struct drm_device *dev,
 				       struct drm_file *file,
-- 
2.17.1



More information about the dri-devel mailing list