All of lore.kernel.org
 help / color / mirror / Atom feed
From: Max Staudt <mstaudt@suse.de>
To: b.zolnierkie@samsung.com, linux-fbdev@vger.kernel.org
Cc: mstaudt@suse.de, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org, tiwai@suse.com, oneukum@suse.com,
	msrb@suse.com, sndirsch@suse.com, michal@markovi.net,
	philm@manjaro.org, bernhard.rosenkranzer@linaro.org
Subject: [RFC PATCH v2 05/13] bootsplash: Add animation support
Date: Wed, 13 Dec 2017 20:47:47 +0100	[thread overview]
Message-ID: <20171213194755.3409-6-mstaudt@suse.de> (raw)
In-Reply-To: <20171213194755.3409-1-mstaudt@suse.de>

Each 'picture' in the splash file can consist of multiple 'blobs'.

If animation is enabled, these blobs become the frames of an animation,
in the order in which they are stored in the file.

Note: There is only one global timer, so all animations happen at
      the same frame rate. It doesn't really make sense to animate
      more than one object at a time anyway.

Furthermore, this patch introduces a check for reusing a framebuffer
where the splash has recently been painted on - in this case, we only
redraw the objects that are animated.

Signed-off-by: Max Staudt <mstaudt@suse.de>
---
 drivers/video/fbdev/core/bootsplash.c          | 62 +++++++++++++++++++++++---
 drivers/video/fbdev/core/bootsplash_internal.h | 13 +++++-
 drivers/video/fbdev/core/bootsplash_load.c     | 21 +++++++++
 drivers/video/fbdev/core/bootsplash_render.c   | 30 ++++++++++++-
 include/uapi/linux/bootsplash_file.h           | 35 ++++++++++++++-
 5 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 815b007f81ca..c8642142cfea 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
 	console_unlock();
 }
 
+static void splash_callback_animation(struct work_struct *ignored)
+{
+	if (bootsplash_would_render_now()) {
+		/* This will also re-schedule this delayed worker */
+		splash_callback_redraw_vc(ignored);
+	}
+}
+
 
 static bool is_fb_compatible(const struct fb_info *info)
 {
@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
  */
 void bootsplash_render_full(struct fb_info *info)
 {
+	bool is_update = false;
+
 	mutex_lock(&splash_state.data_lock);
 
-	if (!is_fb_compatible(info))
-		goto out;
+	/*
+	 * If we've painted on this FB recently, we don't have to do
+	 * the sanity checks and background drawing again.
+	 */
+	if (splash_state.splash_fb == info)
+		is_update = true;
+
+
+	if (!is_update) {
+		/* Check whether we actually support this FB. */
+		splash_state.splash_fb = NULL;
+
+		if (!is_fb_compatible(info))
+			goto out;
+
+		/* Draw the background only once */
+		bootsplash_do_render_background(info, splash_state.file);
 
-	bootsplash_do_render_background(info, splash_state.file);
+		/* Mark this FB as last seen */
+		splash_state.splash_fb = info;
+	}
 
-	bootsplash_do_render_pictures(info, splash_state.file);
+	bootsplash_do_render_pictures(info, splash_state.file, is_update);
 
 	bootsplash_do_render_flush(info);
 
+	bootsplash_do_step_animations(splash_state.file);
+
+	/* Schedule update for animated splash screens */
+	if (splash_state.file->frame_ms > 0)
+		schedule_delayed_work(&splash_state.dwork_animation,
+				      msecs_to_jiffies(
+				      splash_state.file->frame_ms));
+
 out:
 	mutex_unlock(&splash_state.data_lock);
 }
@@ -169,8 +204,14 @@ void bootsplash_enable(void)
 
 	was_enabled = test_and_set_bit(0, &splash_state.enabled);
 
-	if (!was_enabled)
+	if (!was_enabled) {
+		/* Force a full redraw when the splash is re-activated */
+		mutex_lock(&splash_state.data_lock);
+		splash_state.splash_fb = NULL;
+		mutex_unlock(&splash_state.data_lock);
+
 		schedule_work(&splash_state.work_redraw_vc);
+	}
 }
 
 
@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
  */
 static int splash_resume(struct device *device)
 {
+	/*
+	 * Force full redraw on resume since we've probably lost the
+	 * framebuffer's contents meanwhile
+	 */
+	mutex_lock(&splash_state.data_lock);
+	splash_state.splash_fb = NULL;
+	mutex_unlock(&splash_state.data_lock);
+
 	if (bootsplash_would_render_now())
 		schedule_work(&splash_state.work_redraw_vc);
 
@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
 
 static int splash_suspend(struct device *device)
 {
+	cancel_delayed_work_sync(&splash_state.dwork_animation);
 	cancel_work_sync(&splash_state.work_redraw_vc);
 
 	return 0;
@@ -296,6 +346,8 @@ void bootsplash_init(void)
 	set_bit(0, &splash_state.enabled);
 
 	INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
+	INIT_DELAYED_WORK(&splash_state.dwork_animation,
+			  splash_callback_animation);
 
 
 	if (!splash_state.bootfile || !strlen(splash_state.bootfile))
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index 0acb383aa4e3..b3a74835d90f 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -37,6 +37,8 @@ struct splash_pic_priv {
 
 	struct splash_blob_priv *blobs;
 	u16 blobs_loaded;
+
+	u16 anim_nextframe;
 };
 
 
@@ -45,6 +47,12 @@ struct splash_file_priv {
 	const struct splash_file_header *header;
 
 	struct splash_pic_priv *pics;
+
+	/*
+	 * A local copy of the frame delay in the header.
+	 * We modify it to keep the code simple.
+	 */
+	u16 frame_ms;
 };
 
 
@@ -71,6 +79,7 @@ struct splash_priv {
 	struct platform_device *splash_device;
 
 	struct work_struct work_redraw_vc;
+	struct delayed_work dwork_animation;
 
 	/* Splash data structures including lock for everything below */
 	struct mutex data_lock;
@@ -88,8 +97,10 @@ struct splash_priv {
 void bootsplash_do_render_background(struct fb_info *info,
 				     const struct splash_file_priv *fp);
 void bootsplash_do_render_pictures(struct fb_info *info,
-				   const struct splash_file_priv *fp);
+				   const struct splash_file_priv *fp,
+				   bool is_update);
 void bootsplash_do_render_flush(struct fb_info *info);
+void bootsplash_do_step_animations(struct splash_file_priv *fp);
 
 
 void bootsplash_free_file(struct splash_file_priv *fp);
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
index fd807571ab7d..1f661b2d4cc9 100644
--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ b/drivers/video/fbdev/core/bootsplash_load.c
@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 {
 	const struct firmware *fw;
 	struct splash_file_priv *fp;
+	bool have_anim = false;
 	unsigned int i;
 	const u8 *walker;
 
@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 			goto err;
 		}
 
+		if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
+			pr_warn("Picture %u: Unsupported animation type %u.\n",
+				i, ph->anim_type);
+
+			ph->anim_type = SPLASH_ANIM_NONE;
+		}
+
 		pp->pic_header = ph;
 		pp->blobs = vzalloc(ph->num_blobs
 					* sizeof(struct splash_blob_priv));
@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 	/* Walk over pictures and ensure all blob slots are filled */
 	for (i = 0; i < fp->header->num_pics; i++) {
 		struct splash_pic_priv *pp = &fp->pics[i];
+		const struct splash_pic_header *ph = pp->pic_header;
 
 		if (pp->blobs_loaded != pp->pic_header->num_blobs) {
 			pr_err("Picture %u doesn't have all blob slots filled.\n",
@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 
 			goto err;
 		}
+
+		if (ph->anim_type
+		    && ph->num_blobs > 1
+		    && ph->anim_loop < pp->blobs_loaded)
+			have_anim = true;
 	}
 
+	if (!have_anim)
+		/* Disable animation timer if there is nothing to animate */
+		fp->frame_ms = 0;
+	else
+		/* Enforce minimum delay between frames */
+		fp->frame_ms = max((u16)20, fp->header->frame_ms);
+
 	pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
 		fw->size,
 		fp->header->num_pics,
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 07e3a4eab811..76033606ca8a 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
 
 
 void bootsplash_do_render_pictures(struct fb_info *info,
-				   const struct splash_file_priv *fp)
+				   const struct splash_file_priv *fp,
+				   bool is_update)
 {
 	unsigned int i;
 
@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
 		if (pp->blobs_loaded < 1)
 			continue;
 
-		bp = &pp->blobs[0];
+		/* Skip static pictures when refreshing animations */
+		if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
+			continue;
+
+		bp = &pp->blobs[pp->anim_nextframe];
 
 		if (!bp || bp->blob_header->type != 0)
 			continue;
@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
 		info->fbops->fb_copyarea(info, &area);
 	}
 }
+
+
+void bootsplash_do_step_animations(struct splash_file_priv *fp)
+{
+	unsigned int i;
+
+	/* Step every animation once */
+	for (i = 0; i < fp->header->num_pics; i++) {
+		struct splash_pic_priv *pp = &fp->pics[i];
+
+		if (pp->blobs_loaded < 2
+		    || pp->pic_header->anim_loop > pp->blobs_loaded)
+			continue;
+
+		if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) {
+			pp->anim_nextframe++;
+			if (pp->anim_nextframe >= pp->pic_header->num_blobs)
+				pp->anim_nextframe = pp->pic_header->anim_loop;
+		}
+	}
+}
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
index 71cedcc68933..b3af0a3c6487 100644
--- a/include/uapi/linux/bootsplash_file.h
+++ b/include/uapi/linux/bootsplash_file.h
@@ -77,7 +77,17 @@ struct splash_file_header {
 	uint16_t num_blobs;
 	uint8_t num_pics;
 
-	uint8_t padding[103];
+	uint8_t unused_1;
+
+	/*
+	 * Milliseconds to wait before painting the next frame in
+	 * an animation.
+	 * This is actually a minimum, as the system is allowed to
+	 * stall for longer between frames.
+	 */
+	uint16_t frame_ms;
+
+	uint8_t padding[100];
 } __attribute__((__packed__));
 
 
@@ -116,7 +126,23 @@ struct splash_pic_header {
 	 */
 	uint16_t position_offset;
 
-	uint8_t padding[24];
+	/*
+	 * Animation type.
+	 *  0 - off
+	 *  1 - forward loop
+	 */
+	uint8_t anim_type;
+
+	/*
+	 * Animation loop point.
+	 * Actual meaning depends on animation type:
+	 * Type 0 - Unused
+	 *      1 - Frame at which to restart the forward loop
+	 *          (allowing for "intro" frames)
+	 */
+	uint8_t anim_loop;
+
+	uint8_t padding[22];
 } __attribute__((__packed__));
 
 
@@ -158,4 +184,9 @@ enum splash_position {
 	SPLASH_POS_FLAG_CORNER = 0x10,
 };
 
+enum splash_anim_type {
+	SPLASH_ANIM_NONE = 0,
+	SPLASH_ANIM_LOOP_FORWARD = 1,
+};
+
 #endif
-- 
2.12.3

WARNING: multiple messages have this Message-ID (diff)
From: Max Staudt <mstaudt@suse.de>
To: b.zolnierkie@samsung.com, linux-fbdev@vger.kernel.org
Cc: michal@markovi.net, sndirsch@suse.com, oneukum@suse.com,
	tiwai@suse.com, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org, mstaudt@suse.de,
	bernhard.rosenkranzer@linaro.org, philm@manjaro.org
Subject: [RFC PATCH v2 05/13] bootsplash: Add animation support
Date: Wed, 13 Dec 2017 19:47:47 +0000	[thread overview]
Message-ID: <20171213194755.3409-6-mstaudt@suse.de> (raw)
In-Reply-To: <20171213194755.3409-1-mstaudt@suse.de>

Each 'picture' in the splash file can consist of multiple 'blobs'.

If animation is enabled, these blobs become the frames of an animation,
in the order in which they are stored in the file.

Note: There is only one global timer, so all animations happen at
      the same frame rate. It doesn't really make sense to animate
      more than one object at a time anyway.

Furthermore, this patch introduces a check for reusing a framebuffer
where the splash has recently been painted on - in this case, we only
redraw the objects that are animated.

Signed-off-by: Max Staudt <mstaudt@suse.de>
---
 drivers/video/fbdev/core/bootsplash.c          | 62 +++++++++++++++++++++++---
 drivers/video/fbdev/core/bootsplash_internal.h | 13 +++++-
 drivers/video/fbdev/core/bootsplash_load.c     | 21 +++++++++
 drivers/video/fbdev/core/bootsplash_render.c   | 30 ++++++++++++-
 include/uapi/linux/bootsplash_file.h           | 35 ++++++++++++++-
 5 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 815b007f81ca..c8642142cfea 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
 	console_unlock();
 }
 
+static void splash_callback_animation(struct work_struct *ignored)
+{
+	if (bootsplash_would_render_now()) {
+		/* This will also re-schedule this delayed worker */
+		splash_callback_redraw_vc(ignored);
+	}
+}
+
 
 static bool is_fb_compatible(const struct fb_info *info)
 {
@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
  */
 void bootsplash_render_full(struct fb_info *info)
 {
+	bool is_update = false;
+
 	mutex_lock(&splash_state.data_lock);
 
-	if (!is_fb_compatible(info))
-		goto out;
+	/*
+	 * If we've painted on this FB recently, we don't have to do
+	 * the sanity checks and background drawing again.
+	 */
+	if (splash_state.splash_fb = info)
+		is_update = true;
+
+
+	if (!is_update) {
+		/* Check whether we actually support this FB. */
+		splash_state.splash_fb = NULL;
+
+		if (!is_fb_compatible(info))
+			goto out;
+
+		/* Draw the background only once */
+		bootsplash_do_render_background(info, splash_state.file);
 
-	bootsplash_do_render_background(info, splash_state.file);
+		/* Mark this FB as last seen */
+		splash_state.splash_fb = info;
+	}
 
-	bootsplash_do_render_pictures(info, splash_state.file);
+	bootsplash_do_render_pictures(info, splash_state.file, is_update);
 
 	bootsplash_do_render_flush(info);
 
+	bootsplash_do_step_animations(splash_state.file);
+
+	/* Schedule update for animated splash screens */
+	if (splash_state.file->frame_ms > 0)
+		schedule_delayed_work(&splash_state.dwork_animation,
+				      msecs_to_jiffies(
+				      splash_state.file->frame_ms));
+
 out:
 	mutex_unlock(&splash_state.data_lock);
 }
@@ -169,8 +204,14 @@ void bootsplash_enable(void)
 
 	was_enabled = test_and_set_bit(0, &splash_state.enabled);
 
-	if (!was_enabled)
+	if (!was_enabled) {
+		/* Force a full redraw when the splash is re-activated */
+		mutex_lock(&splash_state.data_lock);
+		splash_state.splash_fb = NULL;
+		mutex_unlock(&splash_state.data_lock);
+
 		schedule_work(&splash_state.work_redraw_vc);
+	}
 }
 
 
@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
  */
 static int splash_resume(struct device *device)
 {
+	/*
+	 * Force full redraw on resume since we've probably lost the
+	 * framebuffer's contents meanwhile
+	 */
+	mutex_lock(&splash_state.data_lock);
+	splash_state.splash_fb = NULL;
+	mutex_unlock(&splash_state.data_lock);
+
 	if (bootsplash_would_render_now())
 		schedule_work(&splash_state.work_redraw_vc);
 
@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
 
 static int splash_suspend(struct device *device)
 {
+	cancel_delayed_work_sync(&splash_state.dwork_animation);
 	cancel_work_sync(&splash_state.work_redraw_vc);
 
 	return 0;
@@ -296,6 +346,8 @@ void bootsplash_init(void)
 	set_bit(0, &splash_state.enabled);
 
 	INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
+	INIT_DELAYED_WORK(&splash_state.dwork_animation,
+			  splash_callback_animation);
 
 
 	if (!splash_state.bootfile || !strlen(splash_state.bootfile))
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index 0acb383aa4e3..b3a74835d90f 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -37,6 +37,8 @@ struct splash_pic_priv {
 
 	struct splash_blob_priv *blobs;
 	u16 blobs_loaded;
+
+	u16 anim_nextframe;
 };
 
 
@@ -45,6 +47,12 @@ struct splash_file_priv {
 	const struct splash_file_header *header;
 
 	struct splash_pic_priv *pics;
+
+	/*
+	 * A local copy of the frame delay in the header.
+	 * We modify it to keep the code simple.
+	 */
+	u16 frame_ms;
 };
 
 
@@ -71,6 +79,7 @@ struct splash_priv {
 	struct platform_device *splash_device;
 
 	struct work_struct work_redraw_vc;
+	struct delayed_work dwork_animation;
 
 	/* Splash data structures including lock for everything below */
 	struct mutex data_lock;
@@ -88,8 +97,10 @@ struct splash_priv {
 void bootsplash_do_render_background(struct fb_info *info,
 				     const struct splash_file_priv *fp);
 void bootsplash_do_render_pictures(struct fb_info *info,
-				   const struct splash_file_priv *fp);
+				   const struct splash_file_priv *fp,
+				   bool is_update);
 void bootsplash_do_render_flush(struct fb_info *info);
+void bootsplash_do_step_animations(struct splash_file_priv *fp);
 
 
 void bootsplash_free_file(struct splash_file_priv *fp);
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
index fd807571ab7d..1f661b2d4cc9 100644
--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ b/drivers/video/fbdev/core/bootsplash_load.c
@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 {
 	const struct firmware *fw;
 	struct splash_file_priv *fp;
+	bool have_anim = false;
 	unsigned int i;
 	const u8 *walker;
 
@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 			goto err;
 		}
 
+		if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
+			pr_warn("Picture %u: Unsupported animation type %u.\n",
+				i, ph->anim_type);
+
+			ph->anim_type = SPLASH_ANIM_NONE;
+		}
+
 		pp->pic_header = ph;
 		pp->blobs = vzalloc(ph->num_blobs
 					* sizeof(struct splash_blob_priv));
@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 	/* Walk over pictures and ensure all blob slots are filled */
 	for (i = 0; i < fp->header->num_pics; i++) {
 		struct splash_pic_priv *pp = &fp->pics[i];
+		const struct splash_pic_header *ph = pp->pic_header;
 
 		if (pp->blobs_loaded != pp->pic_header->num_blobs) {
 			pr_err("Picture %u doesn't have all blob slots filled.\n",
@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 
 			goto err;
 		}
+
+		if (ph->anim_type
+		    && ph->num_blobs > 1
+		    && ph->anim_loop < pp->blobs_loaded)
+			have_anim = true;
 	}
 
+	if (!have_anim)
+		/* Disable animation timer if there is nothing to animate */
+		fp->frame_ms = 0;
+	else
+		/* Enforce minimum delay between frames */
+		fp->frame_ms = max((u16)20, fp->header->frame_ms);
+
 	pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
 		fw->size,
 		fp->header->num_pics,
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 07e3a4eab811..76033606ca8a 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
 
 
 void bootsplash_do_render_pictures(struct fb_info *info,
-				   const struct splash_file_priv *fp)
+				   const struct splash_file_priv *fp,
+				   bool is_update)
 {
 	unsigned int i;
 
@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
 		if (pp->blobs_loaded < 1)
 			continue;
 
-		bp = &pp->blobs[0];
+		/* Skip static pictures when refreshing animations */
+		if (ph->anim_type = SPLASH_ANIM_NONE && is_update)
+			continue;
+
+		bp = &pp->blobs[pp->anim_nextframe];
 
 		if (!bp || bp->blob_header->type != 0)
 			continue;
@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
 		info->fbops->fb_copyarea(info, &area);
 	}
 }
+
+
+void bootsplash_do_step_animations(struct splash_file_priv *fp)
+{
+	unsigned int i;
+
+	/* Step every animation once */
+	for (i = 0; i < fp->header->num_pics; i++) {
+		struct splash_pic_priv *pp = &fp->pics[i];
+
+		if (pp->blobs_loaded < 2
+		    || pp->pic_header->anim_loop > pp->blobs_loaded)
+			continue;
+
+		if (pp->pic_header->anim_type = SPLASH_ANIM_LOOP_FORWARD) {
+			pp->anim_nextframe++;
+			if (pp->anim_nextframe >= pp->pic_header->num_blobs)
+				pp->anim_nextframe = pp->pic_header->anim_loop;
+		}
+	}
+}
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
index 71cedcc68933..b3af0a3c6487 100644
--- a/include/uapi/linux/bootsplash_file.h
+++ b/include/uapi/linux/bootsplash_file.h
@@ -77,7 +77,17 @@ struct splash_file_header {
 	uint16_t num_blobs;
 	uint8_t num_pics;
 
-	uint8_t padding[103];
+	uint8_t unused_1;
+
+	/*
+	 * Milliseconds to wait before painting the next frame in
+	 * an animation.
+	 * This is actually a minimum, as the system is allowed to
+	 * stall for longer between frames.
+	 */
+	uint16_t frame_ms;
+
+	uint8_t padding[100];
 } __attribute__((__packed__));
 
 
@@ -116,7 +126,23 @@ struct splash_pic_header {
 	 */
 	uint16_t position_offset;
 
-	uint8_t padding[24];
+	/*
+	 * Animation type.
+	 *  0 - off
+	 *  1 - forward loop
+	 */
+	uint8_t anim_type;
+
+	/*
+	 * Animation loop point.
+	 * Actual meaning depends on animation type:
+	 * Type 0 - Unused
+	 *      1 - Frame at which to restart the forward loop
+	 *          (allowing for "intro" frames)
+	 */
+	uint8_t anim_loop;
+
+	uint8_t padding[22];
 } __attribute__((__packed__));
 
 
@@ -158,4 +184,9 @@ enum splash_position {
 	SPLASH_POS_FLAG_CORNER = 0x10,
 };
 
+enum splash_anim_type {
+	SPLASH_ANIM_NONE = 0,
+	SPLASH_ANIM_LOOP_FORWARD = 1,
+};
+
 #endif
-- 
2.12.3


WARNING: multiple messages have this Message-ID (diff)
From: Max Staudt <mstaudt@suse.de>
To: b.zolnierkie@samsung.com, linux-fbdev@vger.kernel.org
Cc: michal@markovi.net, sndirsch@suse.com, oneukum@suse.com,
	tiwai@suse.com, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org, mstaudt@suse.de,
	bernhard.rosenkranzer@linaro.org, philm@manjaro.org
Subject: [RFC PATCH v2 05/13] bootsplash: Add animation support
Date: Wed, 13 Dec 2017 20:47:47 +0100	[thread overview]
Message-ID: <20171213194755.3409-6-mstaudt@suse.de> (raw)
In-Reply-To: <20171213194755.3409-1-mstaudt@suse.de>

Each 'picture' in the splash file can consist of multiple 'blobs'.

If animation is enabled, these blobs become the frames of an animation,
in the order in which they are stored in the file.

Note: There is only one global timer, so all animations happen at
      the same frame rate. It doesn't really make sense to animate
      more than one object at a time anyway.

Furthermore, this patch introduces a check for reusing a framebuffer
where the splash has recently been painted on - in this case, we only
redraw the objects that are animated.

Signed-off-by: Max Staudt <mstaudt@suse.de>
---
 drivers/video/fbdev/core/bootsplash.c          | 62 +++++++++++++++++++++++---
 drivers/video/fbdev/core/bootsplash_internal.h | 13 +++++-
 drivers/video/fbdev/core/bootsplash_load.c     | 21 +++++++++
 drivers/video/fbdev/core/bootsplash_render.c   | 30 ++++++++++++-
 include/uapi/linux/bootsplash_file.h           | 35 ++++++++++++++-
 5 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
index 815b007f81ca..c8642142cfea 100644
--- a/drivers/video/fbdev/core/bootsplash.c
+++ b/drivers/video/fbdev/core/bootsplash.c
@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
 	console_unlock();
 }
 
+static void splash_callback_animation(struct work_struct *ignored)
+{
+	if (bootsplash_would_render_now()) {
+		/* This will also re-schedule this delayed worker */
+		splash_callback_redraw_vc(ignored);
+	}
+}
+
 
 static bool is_fb_compatible(const struct fb_info *info)
 {
@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
  */
 void bootsplash_render_full(struct fb_info *info)
 {
+	bool is_update = false;
+
 	mutex_lock(&splash_state.data_lock);
 
-	if (!is_fb_compatible(info))
-		goto out;
+	/*
+	 * If we've painted on this FB recently, we don't have to do
+	 * the sanity checks and background drawing again.
+	 */
+	if (splash_state.splash_fb == info)
+		is_update = true;
+
+
+	if (!is_update) {
+		/* Check whether we actually support this FB. */
+		splash_state.splash_fb = NULL;
+
+		if (!is_fb_compatible(info))
+			goto out;
+
+		/* Draw the background only once */
+		bootsplash_do_render_background(info, splash_state.file);
 
-	bootsplash_do_render_background(info, splash_state.file);
+		/* Mark this FB as last seen */
+		splash_state.splash_fb = info;
+	}
 
-	bootsplash_do_render_pictures(info, splash_state.file);
+	bootsplash_do_render_pictures(info, splash_state.file, is_update);
 
 	bootsplash_do_render_flush(info);
 
+	bootsplash_do_step_animations(splash_state.file);
+
+	/* Schedule update for animated splash screens */
+	if (splash_state.file->frame_ms > 0)
+		schedule_delayed_work(&splash_state.dwork_animation,
+				      msecs_to_jiffies(
+				      splash_state.file->frame_ms));
+
 out:
 	mutex_unlock(&splash_state.data_lock);
 }
@@ -169,8 +204,14 @@ void bootsplash_enable(void)
 
 	was_enabled = test_and_set_bit(0, &splash_state.enabled);
 
-	if (!was_enabled)
+	if (!was_enabled) {
+		/* Force a full redraw when the splash is re-activated */
+		mutex_lock(&splash_state.data_lock);
+		splash_state.splash_fb = NULL;
+		mutex_unlock(&splash_state.data_lock);
+
 		schedule_work(&splash_state.work_redraw_vc);
+	}
 }
 
 
@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
  */
 static int splash_resume(struct device *device)
 {
+	/*
+	 * Force full redraw on resume since we've probably lost the
+	 * framebuffer's contents meanwhile
+	 */
+	mutex_lock(&splash_state.data_lock);
+	splash_state.splash_fb = NULL;
+	mutex_unlock(&splash_state.data_lock);
+
 	if (bootsplash_would_render_now())
 		schedule_work(&splash_state.work_redraw_vc);
 
@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
 
 static int splash_suspend(struct device *device)
 {
+	cancel_delayed_work_sync(&splash_state.dwork_animation);
 	cancel_work_sync(&splash_state.work_redraw_vc);
 
 	return 0;
@@ -296,6 +346,8 @@ void bootsplash_init(void)
 	set_bit(0, &splash_state.enabled);
 
 	INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
+	INIT_DELAYED_WORK(&splash_state.dwork_animation,
+			  splash_callback_animation);
 
 
 	if (!splash_state.bootfile || !strlen(splash_state.bootfile))
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
index 0acb383aa4e3..b3a74835d90f 100644
--- a/drivers/video/fbdev/core/bootsplash_internal.h
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
@@ -37,6 +37,8 @@ struct splash_pic_priv {
 
 	struct splash_blob_priv *blobs;
 	u16 blobs_loaded;
+
+	u16 anim_nextframe;
 };
 
 
@@ -45,6 +47,12 @@ struct splash_file_priv {
 	const struct splash_file_header *header;
 
 	struct splash_pic_priv *pics;
+
+	/*
+	 * A local copy of the frame delay in the header.
+	 * We modify it to keep the code simple.
+	 */
+	u16 frame_ms;
 };
 
 
@@ -71,6 +79,7 @@ struct splash_priv {
 	struct platform_device *splash_device;
 
 	struct work_struct work_redraw_vc;
+	struct delayed_work dwork_animation;
 
 	/* Splash data structures including lock for everything below */
 	struct mutex data_lock;
@@ -88,8 +97,10 @@ struct splash_priv {
 void bootsplash_do_render_background(struct fb_info *info,
 				     const struct splash_file_priv *fp);
 void bootsplash_do_render_pictures(struct fb_info *info,
-				   const struct splash_file_priv *fp);
+				   const struct splash_file_priv *fp,
+				   bool is_update);
 void bootsplash_do_render_flush(struct fb_info *info);
+void bootsplash_do_step_animations(struct splash_file_priv *fp);
 
 
 void bootsplash_free_file(struct splash_file_priv *fp);
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
index fd807571ab7d..1f661b2d4cc9 100644
--- a/drivers/video/fbdev/core/bootsplash_load.c
+++ b/drivers/video/fbdev/core/bootsplash_load.c
@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 {
 	const struct firmware *fw;
 	struct splash_file_priv *fp;
+	bool have_anim = false;
 	unsigned int i;
 	const u8 *walker;
 
@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 			goto err;
 		}
 
+		if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
+			pr_warn("Picture %u: Unsupported animation type %u.\n",
+				i, ph->anim_type);
+
+			ph->anim_type = SPLASH_ANIM_NONE;
+		}
+
 		pp->pic_header = ph;
 		pp->blobs = vzalloc(ph->num_blobs
 					* sizeof(struct splash_blob_priv));
@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 	/* Walk over pictures and ensure all blob slots are filled */
 	for (i = 0; i < fp->header->num_pics; i++) {
 		struct splash_pic_priv *pp = &fp->pics[i];
+		const struct splash_pic_header *ph = pp->pic_header;
 
 		if (pp->blobs_loaded != pp->pic_header->num_blobs) {
 			pr_err("Picture %u doesn't have all blob slots filled.\n",
@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
 
 			goto err;
 		}
+
+		if (ph->anim_type
+		    && ph->num_blobs > 1
+		    && ph->anim_loop < pp->blobs_loaded)
+			have_anim = true;
 	}
 
+	if (!have_anim)
+		/* Disable animation timer if there is nothing to animate */
+		fp->frame_ms = 0;
+	else
+		/* Enforce minimum delay between frames */
+		fp->frame_ms = max((u16)20, fp->header->frame_ms);
+
 	pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
 		fw->size,
 		fp->header->num_pics,
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
index 07e3a4eab811..76033606ca8a 100644
--- a/drivers/video/fbdev/core/bootsplash_render.c
+++ b/drivers/video/fbdev/core/bootsplash_render.c
@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
 
 
 void bootsplash_do_render_pictures(struct fb_info *info,
-				   const struct splash_file_priv *fp)
+				   const struct splash_file_priv *fp,
+				   bool is_update)
 {
 	unsigned int i;
 
@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
 		if (pp->blobs_loaded < 1)
 			continue;
 
-		bp = &pp->blobs[0];
+		/* Skip static pictures when refreshing animations */
+		if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
+			continue;
+
+		bp = &pp->blobs[pp->anim_nextframe];
 
 		if (!bp || bp->blob_header->type != 0)
 			continue;
@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
 		info->fbops->fb_copyarea(info, &area);
 	}
 }
+
+
+void bootsplash_do_step_animations(struct splash_file_priv *fp)
+{
+	unsigned int i;
+
+	/* Step every animation once */
+	for (i = 0; i < fp->header->num_pics; i++) {
+		struct splash_pic_priv *pp = &fp->pics[i];
+
+		if (pp->blobs_loaded < 2
+		    || pp->pic_header->anim_loop > pp->blobs_loaded)
+			continue;
+
+		if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) {
+			pp->anim_nextframe++;
+			if (pp->anim_nextframe >= pp->pic_header->num_blobs)
+				pp->anim_nextframe = pp->pic_header->anim_loop;
+		}
+	}
+}
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
index 71cedcc68933..b3af0a3c6487 100644
--- a/include/uapi/linux/bootsplash_file.h
+++ b/include/uapi/linux/bootsplash_file.h
@@ -77,7 +77,17 @@ struct splash_file_header {
 	uint16_t num_blobs;
 	uint8_t num_pics;
 
-	uint8_t padding[103];
+	uint8_t unused_1;
+
+	/*
+	 * Milliseconds to wait before painting the next frame in
+	 * an animation.
+	 * This is actually a minimum, as the system is allowed to
+	 * stall for longer between frames.
+	 */
+	uint16_t frame_ms;
+
+	uint8_t padding[100];
 } __attribute__((__packed__));
 
 
@@ -116,7 +126,23 @@ struct splash_pic_header {
 	 */
 	uint16_t position_offset;
 
-	uint8_t padding[24];
+	/*
+	 * Animation type.
+	 *  0 - off
+	 *  1 - forward loop
+	 */
+	uint8_t anim_type;
+
+	/*
+	 * Animation loop point.
+	 * Actual meaning depends on animation type:
+	 * Type 0 - Unused
+	 *      1 - Frame at which to restart the forward loop
+	 *          (allowing for "intro" frames)
+	 */
+	uint8_t anim_loop;
+
+	uint8_t padding[22];
 } __attribute__((__packed__));
 
 
@@ -158,4 +184,9 @@ enum splash_position {
 	SPLASH_POS_FLAG_CORNER = 0x10,
 };
 
+enum splash_anim_type {
+	SPLASH_ANIM_NONE = 0,
+	SPLASH_ANIM_LOOP_FORWARD = 1,
+};
+
 #endif
-- 
2.12.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2017-12-13 19:50 UTC|newest]

Thread overview: 193+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-13 19:47 [RFC PATCH v2 00/13] Kernel based bootsplash Max Staudt
2017-12-13 19:47 ` Max Staudt
2017-12-13 19:47 ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 01/13] bootsplash: Initial implementation showing black screen Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 23:55   ` Randy Dunlap
2017-12-13 23:55     ` Randy Dunlap
2017-12-14 15:37     ` Max Staudt
2017-12-14 15:37       ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 02/13] bootsplash: Add file reading and picture rendering Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 03/13] bootsplash: Flush framebuffer after drawing Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 21:35   ` Daniel Vetter
2017-12-13 21:35     ` Daniel Vetter
2017-12-13 21:35     ` Daniel Vetter
2017-12-14 15:36     ` Max Staudt
2017-12-14 15:36       ` Max Staudt
2017-12-14 15:36       ` Max Staudt
2017-12-19 12:23       ` Daniel Vetter
2017-12-19 12:23         ` Daniel Vetter
2017-12-19 12:23         ` Daniel Vetter
2017-12-19 13:34         ` Max Staudt
2017-12-19 13:34           ` Max Staudt
2017-12-19 13:34           ` Max Staudt
2017-12-19 13:57           ` Daniel Vetter
2017-12-19 13:57             ` Daniel Vetter
2017-12-19 14:07             ` Oliver Neukum
2017-12-19 14:07               ` Oliver Neukum
2017-12-31 12:53               ` Alan Cox
2017-12-31 12:53                 ` Alan Cox
2017-12-31 12:53                 ` Alan Cox
2018-01-03 18:04                 ` Max Staudt
2018-01-03 18:04                   ` Max Staudt
2018-01-03 18:04                   ` Max Staudt
2017-12-19 15:41             ` Max Staudt
2017-12-19 15:41               ` Max Staudt
2017-12-19 15:41               ` Max Staudt
2017-12-19 16:02               ` Daniel Vetter
2017-12-19 16:02                 ` Daniel Vetter
2017-12-19 16:02                 ` Daniel Vetter
2017-12-19 16:23                 ` Max Staudt
2017-12-19 16:23                   ` Max Staudt
2017-12-19 16:23                   ` Max Staudt
2017-12-20  9:45                   ` Daniel Vetter
2017-12-20  9:45                     ` Daniel Vetter
2017-12-20  9:45                     ` Daniel Vetter
2017-12-19 16:09               ` Daniel Vetter
2017-12-19 16:09                 ` Daniel Vetter
2017-12-19 16:09                 ` Daniel Vetter
2017-12-19 16:26                 ` Max Staudt
2017-12-19 16:26                   ` Max Staudt
2017-12-19 16:26                   ` Max Staudt
2017-12-19 21:01               ` Ray Strode
2017-12-19 21:01                 ` Ray Strode
2017-12-19 21:01                 ` Ray Strode
2017-12-20 13:14                 ` Max Staudt
2017-12-20 13:14                   ` Max Staudt
2017-12-20 13:14                   ` Max Staudt
2017-12-20 15:35                   ` Ray Strode
2017-12-20 15:35                     ` Ray Strode
2017-12-20 15:35                     ` Ray Strode
2017-12-20 16:52                     ` Max Staudt
2017-12-20 16:52                       ` Max Staudt
2017-12-20 16:52                       ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 04/13] bootsplash: Add corner positioning Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` Max Staudt [this message]
2017-12-13 19:47   ` [RFC PATCH v2 05/13] bootsplash: Add animation support Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 06/13] vt: Redraw bootsplash fully on console_unblank Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 07/13] vt: Add keyboard hook to disable bootsplash Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 08/13] sysrq: Disable bootsplash on SAK Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 09/13] fbcon: Disable bootsplash on oops Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 10/13] Documentation: Add bootsplash main documentation Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 11/13] bootsplash: sysfs entries to load and unload files Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 12/13] tools/bootsplash: Add a basic splash file creation tool Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47 ` [RFC PATCH v2 13/13] tools/bootsplash: Add script and data to create sample file Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:47   ` Max Staudt
2017-12-13 19:52 ` [RFC PATCH v2 00/13] Kernel based bootsplash Max Staudt
2017-12-13 19:52   ` Max Staudt
2017-12-13 19:52   ` Max Staudt
2017-12-19 16:16 ` Daniel Vetter
2017-12-19 16:16   ` Daniel Vetter
2017-12-19 16:16   ` Daniel Vetter
2017-12-19 17:04   ` Max Staudt
2017-12-19 17:04     ` Max Staudt
2017-12-19 17:04     ` Max Staudt
2017-12-19 17:26     ` Daniel Vetter
2017-12-19 17:26       ` Daniel Vetter
2017-12-19 17:26       ` Daniel Vetter
2017-12-19 18:40       ` Max Staudt
2017-12-19 18:40         ` Max Staudt
2017-12-19 18:40         ` Max Staudt
2017-12-20  9:43         ` Daniel Vetter
2017-12-20  9:43           ` Daniel Vetter
2017-12-20  9:43           ` Daniel Vetter
2017-12-20 10:06           ` Neil Armstrong
2017-12-20 10:06             ` Neil Armstrong
2017-12-20 10:06             ` Neil Armstrong
2017-12-20 10:14             ` Daniel Vetter
2017-12-20 10:14               ` Daniel Vetter
2017-12-20 10:14               ` Daniel Vetter
2017-12-20 14:55               ` Max Staudt
2017-12-20 14:55                 ` Max Staudt
2017-12-20 15:11                 ` Daniel Vetter
2017-12-20 15:11                   ` Daniel Vetter
2017-12-20 15:11                   ` Daniel Vetter
2017-12-20 15:19                   ` Daniel Vetter
2017-12-20 15:19                     ` Daniel Vetter
2017-12-20 15:19                     ` Daniel Vetter
2017-12-20 15:22                     ` Daniel Vetter
2017-12-20 15:22                       ` Daniel Vetter
2017-12-20 15:22                       ` Daniel Vetter
2017-12-20 16:23                     ` Max Staudt
2017-12-20 16:23                       ` Max Staudt
2017-12-20 16:23                       ` Max Staudt
2017-12-20 16:15                   ` Max Staudt
2017-12-20 16:15                     ` Max Staudt
2017-12-20 16:15                     ` Max Staudt
2017-12-31 12:44                   ` Alan Cox
2017-12-31 12:44                     ` Alan Cox
2017-12-31 12:44                     ` Alan Cox
2018-01-03 18:00                     ` Max Staudt
2018-01-03 18:00                       ` Max Staudt
2017-12-20 14:16             ` Max Staudt
2017-12-20 14:16               ` Max Staudt
2017-12-20 14:16               ` Max Staudt
2017-12-20 14:10           ` Max Staudt
2017-12-20 14:10             ` Max Staudt
2017-12-20 14:10             ` Max Staudt
2017-12-31 12:35         ` Alan Cox
2017-12-31 12:35           ` Alan Cox
2017-12-31 12:35           ` Alan Cox
2018-01-03 17:56           ` Max Staudt
2018-01-03 17:56             ` Max Staudt
2018-01-03 17:56             ` Max Staudt
2017-12-19 20:30     ` Ray Strode
2017-12-19 20:30       ` Ray Strode
2017-12-19 20:30       ` Ray Strode
2017-12-20 13:03       ` Max Staudt
2017-12-20 13:03         ` Max Staudt
2017-12-20 13:03         ` Max Staudt
2017-12-20 15:21         ` Ray Strode
2017-12-20 15:21           ` Ray Strode
2017-12-20 15:21           ` Ray Strode
2017-12-20 16:44           ` Max Staudt
2017-12-20 16:44             ` Max Staudt
2017-12-20 16:44             ` Max Staudt
2017-12-21 14:51             ` Ray Strode
2017-12-21 14:51               ` Ray Strode
2017-12-21 14:51               ` Ray Strode
2017-12-21 16:32               ` Max Staudt
2017-12-21 16:32                 ` Max Staudt
2017-12-20 11:08   ` Johannes Thumshirn
2017-12-20 11:08     ` Johannes Thumshirn
2017-12-20 11:22     ` Daniel Stone
2017-12-20 11:22       ` Daniel Stone
2017-12-20 11:22       ` Daniel Stone
2017-12-20 12:48       ` Johannes Thumshirn
2017-12-20 12:48         ` Johannes Thumshirn
2017-12-29 17:13   ` Jani Nikula
2017-12-29 17:13     ` Jani Nikula
2017-12-29 17:13     ` Jani Nikula
2018-01-03 17:38     ` Max Staudt
2018-01-03 17:38       ` Max Staudt
2017-12-21  9:48 ` Daniel Vetter
2017-12-21  9:48   ` Daniel Vetter
2017-12-21  9:48   ` Daniel Vetter
2017-12-21 16:52   ` Max Staudt
2017-12-21 16:52     ` Max Staudt
2017-12-21 16:52     ` Max Staudt
2017-12-21 15:00 ` Philip Müller
2017-12-21 15:00   ` Philip Müller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171213194755.3409-6-mstaudt@suse.de \
    --to=mstaudt@suse.de \
    --cc=b.zolnierkie@samsung.com \
    --cc=bernhard.rosenkranzer@linaro.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michal@markovi.net \
    --cc=msrb@suse.com \
    --cc=oneukum@suse.com \
    --cc=philm@manjaro.org \
    --cc=sndirsch@suse.com \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.