[PATCH 3/5] drm/i915: Synchronize userspace palette LUT (i.e. gamma) changes to vblank

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Adam Jackson was watching the screensaver fade out and expressed a
desire for the gamma updates to be synchronized to vblank to avoid the
unsightly tears.

Reported-by: Adam Jackson <ajax at redhat.com>
Cc: Adam Jackson <ajax at redhat.com>
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c | 61 ++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index dc4bf49..279474a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -44,6 +44,7 @@
 bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
 static void intel_increase_pllclock(struct drm_crtc *crtc);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
+static void __intel_crtc_load_lut(struct intel_crtc *crtc, void *data);
 
 static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 				struct intel_crtc_config *pipe_config);
@@ -3457,7 +3458,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 	 * On ILK+ LUT must be loaded before the pipe is running but with
 	 * clocks enabled
 	 */
-	intel_crtc_load_lut(crtc);
+	__intel_crtc_load_lut(to_intel_crtc(crtc), NULL);
 
 	intel_ddi_set_pipe_settings(crtc);
 	intel_ddi_enable_transcoder_func(crtc);
@@ -6411,47 +6412,58 @@ void intel_write_eld(struct drm_encoder *encoder,
 		dev_priv->display.write_eld(connector, crtc);
 }
 
-/** Loads the palette/gamma unit for the CRTC with the prepared values */
-void intel_crtc_load_lut(struct drm_crtc *crtc)
+static void __intel_crtc_load_lut(struct intel_crtc *crtc,
+				  void *data)
 {
-	struct drm_device *dev = crtc->dev;
+	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	int palreg = PALETTE(pipe);
-	int i;
+	enum pipe pipe = crtc->pipe;
 	bool reenable_ips = false;
+	int reg, i;
 
-	/* The clocks have to be on to load the palette. */
-	if (!crtc->enabled || !intel_crtc->active)
+	if (!crtc->base.enabled || !crtc->active)
 		return;
 
-	if (!HAS_PCH_SPLIT(dev_priv->dev))
+	if (!HAS_PCH_SPLIT(dev))
 		assert_pll_enabled(dev_priv, pipe);
 
-	/* use legacy palette for Ironlake */
-	if (HAS_PCH_SPLIT(dev))
-		palreg = LGC_PALETTE(pipe);
-
 	/* Workaround : Do not read or write the pipe palette/gamma data while
 	 * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
 	 */
-	if (intel_crtc->config.ips_enabled &&
+	if (crtc->config.ips_enabled &&
 	    ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
 	     GAMMA_MODE_MODE_SPLIT)) {
-		hsw_disable_ips(intel_crtc);
+		hsw_disable_ips(crtc);
 		reenable_ips = true;
 	}
 
-	for (i = 0; i < 256; i++) {
-		I915_WRITE(palreg + 4 * i,
-			   (intel_crtc->lut_r[i] << 16) |
-			   (intel_crtc->lut_g[i] << 8) |
-			   intel_crtc->lut_b[i]);
-	}
+	/* use legacy palette for Ironlake */
+	reg = PALETTE(pipe);
+	if (HAS_PCH_SPLIT(crtc->base.dev))
+		reg = LGC_PALETTE(pipe);
+
+	for (i = 0; i < 256; i++)
+		I915_WRITE(reg + 4 * i,
+			   crtc->lut_r[i] << 16 |
+			   crtc->lut_g[i] << 8  |
+			   crtc->lut_b[i]);
 
 	if (reenable_ips)
-		hsw_enable_ips(intel_crtc);
+		hsw_enable_ips(crtc);
+}
+
+/** Loads the palette/gamma unit for the CRTC with the prepared values */
+void intel_crtc_load_lut(struct drm_crtc *crtc)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	/* The clocks have to be on to load the palette. */
+	if (!crtc->enabled || !intel_crtc->active)
+		return;
+
+	if (intel_crtc_add_vblank_task(intel_crtc, true,
+				       __intel_crtc_load_lut, NULL))
+		__intel_crtc_load_lut(intel_crtc, NULL);
 }
 
 static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
@@ -6749,6 +6761,7 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 	int end = (start + size > 256) ? 256 : start + size, i;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
+	/* We race here with setting the lut and reading it during vblank. */
 	for (i = start; i < end; i++) {
 		intel_crtc->lut_r[i] = red[i] >> 8;
 		intel_crtc->lut_g[i] = green[i] >> 8;
-- 
1.8.3.2



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux