diff mbox

[6/6] drm/i915: New drm crtc property for varying the Crtc size

Message ID 1408008267-11443-7-git-send-email-akash.goel@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

akash.goel@intel.com Aug. 14, 2014, 9:24 a.m. UTC
From: Akash Goel <akash.goel@intel.com>

This patch adds a new drm crtc property for varying the Pipe Src size
or the Panel fitter input size. Pipe Src controls the size that is
scaled from.
This will allow to dynamically flip the frame buffers
of different resolutions.
For this Driver internally enables the Panel fitter or Hw scaler
if its a Fixed mode panel & new Pipe Src values differ from the
Pipe timings

Signed-off-by: Akash Goel <akash.goel@intel.com>
Signed-off-by: Pallavi G<pallavi.g@intel.com>
---
 drivers/gpu/drm/drm_crtc.c           |  7 ++++
 drivers/gpu/drm/drm_fb_helper.c      |  7 ++++
 drivers/gpu/drm/i915/intel_display.c | 72 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h               |  7 ++++
 4 files changed, 93 insertions(+)

Comments

Daniel Vetter Aug. 14, 2014, 2:42 p.m. UTC | #1
On Thu, Aug 14, 2014 at 02:54:27PM +0530, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
> +		/* Check if the current FB is compatible with new requested
> +		   Pipesrc values by the User */
> +		if (new_width > fb->width ||
> +			new_height > fb->height ||
> +			crtc->x > fb->width - new_width ||
> +			crtc->y > fb->height - new_height) {
> +			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
> +			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
> +			return -EINVAL;
> +		}

I think this part here is the achilles heel of your approach. Right now we
use crtc->mode.hdisplay/vdisplay in a lot of places both in i915 and the
drm core to make sure that the primary plane fb, sprite fb and positioning
and cursor placement all make sense.

If my understanding of the pipe src rectangle is correct (please correct
me if I'm wrong) we should switch _all_ these checks to instead look at
the new crtc_w/h field. Even worse that we need to change drm core code
and as a result of that all drm drivers. Awful lot of code to check, test
and for i915 validate with i-g-t testcases.

Now the solution thus far (for the normal panel fitter operation) is that
the logical input mode for the crtc ends up in crtc->config.mode and as a
copy in crtc->mode. And the actual output mode is in
crtc->config.adjusted_mode.

Our modeset code already takes care of copying crtc->config.mode to
crtc->mode, so we only need to concern ourselfs with crtc->config.mode. If
we'd copy the pipe_src_w/h values back into it the existing code would
still be able to check all the sprite/cursor/fb constraints.

So the flow on a modeset (and that's what we'll end up calling from the
set_property function too) is:

1. Userspace requested mode goes into pipe_config->mode.
2. We make a copy into pipe_config->adjusted_mode and frob it more.
3. crtc compute_config code notices the special pipe src window, and
adjusts pipe_config->mode plus computes the panel fitter configuration.

If all that checks out we continue with the modeset sequence.

4. We store the new pipe_config into crtc->config.
5. Actual hw register writes for the modeset change happens.
6. We copy crtc->config.mode into crtc->mode so that drm core and helper
functions can validate fb/sprite/cursors again.

The result would be that the set_property function here would do _no_
argument checking, but would instead fully rely upon the modeset sequence
to compute the desired configuration. And if it fails it would restore the
old configuration like you already do.

Now test coverage: I think we need a few i-g-ts that provoke this, i.e.
which set the pipe_src != requested mode and then place cursor/sprite/fb
to validate that the checking is still correct.

Aside: In the shiny new world of atomic display updates we always need to
have similar procedures i.e.

1. Store state without much checking.
2. Run full modeset machinery to compute the new resulting state.
3. Check that, and only if that checks out, commit it.

If we duplicate special cases of these checks all over, then we'll have an
unmaintainable mess in shorter order. C.f. compare the discussion about
rotation properties.

Thoughts, better ideas and issues with this plan?

Thanks, Daniel
Ville Syrjala Aug. 14, 2014, 3:06 p.m. UTC | #2
On Thu, Aug 14, 2014 at 04:42:01PM +0200, Daniel Vetter wrote:
> On Thu, Aug 14, 2014 at 02:54:27PM +0530, akash.goel@intel.com wrote:
> > From: Akash Goel <akash.goel@intel.com>
> > +		/* Check if the current FB is compatible with new requested
> > +		   Pipesrc values by the User */
> > +		if (new_width > fb->width ||
> > +			new_height > fb->height ||
> > +			crtc->x > fb->width - new_width ||
> > +			crtc->y > fb->height - new_height) {
> > +			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
> > +			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
> > +			return -EINVAL;
> > +		}
> 
> I think this part here is the achilles heel of your approach. Right now we
> use crtc->mode.hdisplay/vdisplay

We don't use it in i915. If we do that's a bug. All the relevant places
should be loooking at pipe_src_{w,h}. In the core the viewport check
should be about the only place that cares about this stuff.

> in a lot of places both in i915 and the
> drm core to make sure that the primary plane fb, sprite fb and positioning
> and cursor placement all make sense.
> 
> If my understanding of the pipe src rectangle is correct (please correct
> me if I'm wrong) we should switch _all_ these checks to instead look at
> the new crtc_w/h field. Even worse that we need to change drm core code
> and as a result of that all drm drivers. Awful lot of code to check, test
> and for i915 validate with i-g-t testcases.
> 
> Now the solution thus far (for the normal panel fitter operation) is that
> the logical input mode for the crtc ends up in crtc->config.mode and as a
> copy in crtc->mode. And the actual output mode is in
> crtc->config.adjusted_mode.
> 
> Our modeset code already takes care of copying crtc->config.mode to
> crtc->mode, so we only need to concern ourselfs with crtc->config.mode. If
> we'd copy the pipe_src_w/h values back into it the existing code would
> still be able to check all the sprite/cursor/fb constraints.
> 
> So the flow on a modeset (and that's what we'll end up calling from the
> set_property function too) is:
> 
> 1. Userspace requested mode goes into pipe_config->mode.
> 2. We make a copy into pipe_config->adjusted_mode and frob it more.
> 3. crtc compute_config code notices the special pipe src window, and
> adjusts pipe_config->mode plus computes the panel fitter configuration.
> 
> If all that checks out we continue with the modeset sequence.
> 
> 4. We store the new pipe_config into crtc->config.
> 5. Actual hw register writes for the modeset change happens.
> 6. We copy crtc->config.mode into crtc->mode so that drm core and helper
> functions can validate fb/sprite/cursors again.

We shouldn't just magically change the user specified mode, we need it
to stay intact for a subsequent modeset so that we can start the
adjusted_mode frobbery fresh next time around. It also seems weird to
report back a different mode to userspace than what the user provided.
What you suggest was exactly the previous approach and I NAKed it.

> The result would be that the set_property function here would do _no_
> argument checking, but would instead fully rely upon the modeset sequence
> to compute the desired configuration.

We don't have sufficient checks in the modeset path. The
drm_crtc_check_viewport() call is in drm_mode_setcrtc() which is too
high up in the stack to affect modesets originating from property
changes. That being said we should definitely use drm_crtc_check_viewport()
here instead of hand rolling the exacty same thing in i915.

And to avoid having to touch too much code, drm_crtc_check_viewport()
should encapsulate the logic to fall back to mode->{h,v}display when
crtc->{w,h} are zero.

> And if it fails it would restore the
> old configuration like you already do.
> 
> Now test coverage: I think we need a few i-g-ts that provoke this, i.e.
> which set the pipe_src != requested mode and then place cursor/sprite/fb
> to validate that the checking is still correct.
> 
> Aside: In the shiny new world of atomic display updates we always need to
> have similar procedures i.e.
> 
> 1. Store state without much checking.
> 2. Run full modeset machinery to compute the new resulting state.
> 3. Check that, and only if that checks out, commit it.
> 
> If we duplicate special cases of these checks all over, then we'll have an
> unmaintainable mess in shorter order. C.f. compare the discussion about
> rotation properties.
> 
> Thoughts, better ideas and issues with this plan?
> 
> Thanks, Daniel
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Daniel Vetter Aug. 14, 2014, 3:26 p.m. UTC | #3
On Thu, Aug 14, 2014 at 06:06:58PM +0300, Ville Syrjälä wrote:
> On Thu, Aug 14, 2014 at 04:42:01PM +0200, Daniel Vetter wrote:
> > On Thu, Aug 14, 2014 at 02:54:27PM +0530, akash.goel@intel.com wrote:
> > > From: Akash Goel <akash.goel@intel.com>
> > > +		/* Check if the current FB is compatible with new requested
> > > +		   Pipesrc values by the User */
> > > +		if (new_width > fb->width ||
> > > +			new_height > fb->height ||
> > > +			crtc->x > fb->width - new_width ||
> > > +			crtc->y > fb->height - new_height) {
> > > +			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
> > > +			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
> > > +			return -EINVAL;
> > > +		}
> > 
> > I think this part here is the achilles heel of your approach. Right now we
> > use crtc->mode.hdisplay/vdisplay
> 
> We don't use it in i915. If we do that's a bug. All the relevant places
> should be loooking at pipe_src_{w,h}. In the core the viewport check
> should be about the only place that cares about this stuff.

Well within i915, but not anywhere in the drm core or helper code since
they're simply not aware of pipe_src_w/h. E.g. the plane helper code also
uses crtc->mode.h/vdisplay.

Changing that basic drm assumption is really invasive imo.

> > in a lot of places both in i915 and the
> > drm core to make sure that the primary plane fb, sprite fb and positioning
> > and cursor placement all make sense.
> > 
> > If my understanding of the pipe src rectangle is correct (please correct
> > me if I'm wrong) we should switch _all_ these checks to instead look at
> > the new crtc_w/h field. Even worse that we need to change drm core code
> > and as a result of that all drm drivers. Awful lot of code to check, test
> > and for i915 validate with i-g-t testcases.
> > 
> > Now the solution thus far (for the normal panel fitter operation) is that
> > the logical input mode for the crtc ends up in crtc->config.mode and as a
> > copy in crtc->mode. And the actual output mode is in
> > crtc->config.adjusted_mode.
> > 
> > Our modeset code already takes care of copying crtc->config.mode to
> > crtc->mode, so we only need to concern ourselfs with crtc->config.mode. If
> > we'd copy the pipe_src_w/h values back into it the existing code would
> > still be able to check all the sprite/cursor/fb constraints.
> > 
> > So the flow on a modeset (and that's what we'll end up calling from the
> > set_property function too) is:
> > 
> > 1. Userspace requested mode goes into pipe_config->mode.
> > 2. We make a copy into pipe_config->adjusted_mode and frob it more.
> > 3. crtc compute_config code notices the special pipe src window, and
> > adjusts pipe_config->mode plus computes the panel fitter configuration.
> > 
> > If all that checks out we continue with the modeset sequence.
> > 
> > 4. We store the new pipe_config into crtc->config.
> > 5. Actual hw register writes for the modeset change happens.
> > 6. We copy crtc->config.mode into crtc->mode so that drm core and helper
> > functions can validate fb/sprite/cursors again.
> 
> We shouldn't just magically change the user specified mode, we need it
> to stay intact for a subsequent modeset so that we can start the
> adjusted_mode frobbery fresh next time around. It also seems weird to
> report back a different mode to userspace than what the user provided.
> What you suggest was exactly the previous approach and I NAKed it.

Oh I'm fully aware that it's in the leagues of cross hacks ;-) But doing
the crtc->src_w/h thing correctly rolled out across the entire drm
subsystem will be a big chunk more work than just adding new variables to
struct drm_crtc which are only used in i915.

> > The result would be that the set_property function here would do _no_
> > argument checking, but would instead fully rely upon the modeset sequence
> > to compute the desired configuration.
> 
> We don't have sufficient checks in the modeset path. The
> drm_crtc_check_viewport() call is in drm_mode_setcrtc() which is too
> high up in the stack to affect modesets originating from property
> changes. That being said we should definitely use drm_crtc_check_viewport()
> here instead of hand rolling the exacty same thing in i915.

I guess then it needs to be moved down eventually.

> And to avoid having to touch too much code, drm_crtc_check_viewport()
> should encapsulate the logic to fall back to mode->{h,v}display when
> crtc->{w,h} are zero.

Actually you get to do a full drm audit anyway, since there's more than
check_viewport. They should all switch to crtc->src_w/h, and we should
fill that out by default in the crtc helpers. Imo stuffing magic new stuff
into the core only used by one driver isn't good, if we go this route we
should do it properly.

Or we ditch the struct drm_crtc change and pull it all into i915.
-Daniel
Ville Syrjala Aug. 14, 2014, 3:32 p.m. UTC | #4
On Thu, Aug 14, 2014 at 05:26:27PM +0200, Daniel Vetter wrote:
> On Thu, Aug 14, 2014 at 06:06:58PM +0300, Ville Syrjälä wrote:
> > On Thu, Aug 14, 2014 at 04:42:01PM +0200, Daniel Vetter wrote:
> > > On Thu, Aug 14, 2014 at 02:54:27PM +0530, akash.goel@intel.com wrote:
> > > > From: Akash Goel <akash.goel@intel.com>
> > > > +		/* Check if the current FB is compatible with new requested
> > > > +		   Pipesrc values by the User */
> > > > +		if (new_width > fb->width ||
> > > > +			new_height > fb->height ||
> > > > +			crtc->x > fb->width - new_width ||
> > > > +			crtc->y > fb->height - new_height) {
> > > > +			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
> > > > +			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
> > > > +			return -EINVAL;
> > > > +		}
> > > 
> > > I think this part here is the achilles heel of your approach. Right now we
> > > use crtc->mode.hdisplay/vdisplay
> > 
> > We don't use it in i915. If we do that's a bug. All the relevant places
> > should be loooking at pipe_src_{w,h}. In the core the viewport check
> > should be about the only place that cares about this stuff.
> 
> Well within i915, but not anywhere in the drm core or helper code since
> they're simply not aware of pipe_src_w/h. E.g. the plane helper code also
> uses crtc->mode.h/vdisplay.
> 
> Changing that basic drm assumption is really invasive imo.
> 
> > > in a lot of places both in i915 and the
> > > drm core to make sure that the primary plane fb, sprite fb and positioning
> > > and cursor placement all make sense.
> > > 
> > > If my understanding of the pipe src rectangle is correct (please correct
> > > me if I'm wrong) we should switch _all_ these checks to instead look at
> > > the new crtc_w/h field. Even worse that we need to change drm core code
> > > and as a result of that all drm drivers. Awful lot of code to check, test
> > > and for i915 validate with i-g-t testcases.
> > > 
> > > Now the solution thus far (for the normal panel fitter operation) is that
> > > the logical input mode for the crtc ends up in crtc->config.mode and as a
> > > copy in crtc->mode. And the actual output mode is in
> > > crtc->config.adjusted_mode.
> > > 
> > > Our modeset code already takes care of copying crtc->config.mode to
> > > crtc->mode, so we only need to concern ourselfs with crtc->config.mode. If
> > > we'd copy the pipe_src_w/h values back into it the existing code would
> > > still be able to check all the sprite/cursor/fb constraints.
> > > 
> > > So the flow on a modeset (and that's what we'll end up calling from the
> > > set_property function too) is:
> > > 
> > > 1. Userspace requested mode goes into pipe_config->mode.
> > > 2. We make a copy into pipe_config->adjusted_mode and frob it more.
> > > 3. crtc compute_config code notices the special pipe src window, and
> > > adjusts pipe_config->mode plus computes the panel fitter configuration.
> > > 
> > > If all that checks out we continue with the modeset sequence.
> > > 
> > > 4. We store the new pipe_config into crtc->config.
> > > 5. Actual hw register writes for the modeset change happens.
> > > 6. We copy crtc->config.mode into crtc->mode so that drm core and helper
> > > functions can validate fb/sprite/cursors again.
> > 
> > We shouldn't just magically change the user specified mode, we need it
> > to stay intact for a subsequent modeset so that we can start the
> > adjusted_mode frobbery fresh next time around. It also seems weird to
> > report back a different mode to userspace than what the user provided.
> > What you suggest was exactly the previous approach and I NAKed it.
> 
> Oh I'm fully aware that it's in the leagues of cross hacks ;-) But doing
> the crtc->src_w/h thing correctly rolled out across the entire drm
> subsystem will be a big chunk more work than just adding new variables to
> struct drm_crtc which are only used in i915.
> 
> > > The result would be that the set_property function here would do _no_
> > > argument checking, but would instead fully rely upon the modeset sequence
> > > to compute the desired configuration.
> > 
> > We don't have sufficient checks in the modeset path. The
> > drm_crtc_check_viewport() call is in drm_mode_setcrtc() which is too
> > high up in the stack to affect modesets originating from property
> > changes. That being said we should definitely use drm_crtc_check_viewport()
> > here instead of hand rolling the exacty same thing in i915.
> 
> I guess then it needs to be moved down eventually.
> 
> > And to avoid having to touch too much code, drm_crtc_check_viewport()
> > should encapsulate the logic to fall back to mode->{h,v}display when
> > crtc->{w,h} are zero.
> 
> Actually you get to do a full drm audit anyway, since there's more than
> check_viewport. They should all switch to crtc->src_w/h, and we should
> fill that out by default in the crtc helpers. Imo stuffing magic new stuff
> into the core only used by one driver isn't good, if we go this route we
> should do it properly.
> 
> Or we ditch the struct drm_crtc change and pull it all into i915.

We can't since we need to get past drm_crtc_check_viewport().
Ville Syrjala Aug. 14, 2014, 3:45 p.m. UTC | #5
On Thu, Aug 14, 2014 at 05:26:27PM +0200, Daniel Vetter wrote:
> On Thu, Aug 14, 2014 at 06:06:58PM +0300, Ville Syrjälä wrote:
> > On Thu, Aug 14, 2014 at 04:42:01PM +0200, Daniel Vetter wrote:
> > > On Thu, Aug 14, 2014 at 02:54:27PM +0530, akash.goel@intel.com wrote:
> > > > From: Akash Goel <akash.goel@intel.com>
> > > > +		/* Check if the current FB is compatible with new requested
> > > > +		   Pipesrc values by the User */
> > > > +		if (new_width > fb->width ||
> > > > +			new_height > fb->height ||
> > > > +			crtc->x > fb->width - new_width ||
> > > > +			crtc->y > fb->height - new_height) {
> > > > +			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
> > > > +			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
> > > > +			return -EINVAL;
> > > > +		}
> > > 
> > > I think this part here is the achilles heel of your approach. Right now we
> > > use crtc->mode.hdisplay/vdisplay
> > 
> > We don't use it in i915. If we do that's a bug. All the relevant places
> > should be loooking at pipe_src_{w,h}. In the core the viewport check
> > should be about the only place that cares about this stuff.
> 
> Well within i915, but not anywhere in the drm core or helper code since
> they're simply not aware of pipe_src_w/h. E.g. the plane helper code also
> uses crtc->mode.h/vdisplay.

My quick grep audit tells me the viewport check and
drm_primary_helper_update() are the only places in the core that care.
The latter is rather dubious anyway since the clipping should be done
against the adjusted mode and not the user specified mode, so anyone
using that is already dancing on thin ice.

The other drivers are something I would not touch. Given how many places
we had to frob in i915 I'm somewhat sure I'd not like what I see there
and then any patch I might cook up would be too half assed to satisfy my
quality standards anyway.

As far as always filling the crtc->w,h always goes, I'm not sure that's
the best idea anyway since we still need the "0 is special" handling.
Well, we could fill them out, but then we definitely need a flag or
something to indicate that they came from the mode and not the
properties, so that we know whether we should overwrite them from
with {h,v}display during a subsquent modeset or if they should keep
their current value.
Daniel Vetter Aug. 14, 2014, 4:07 p.m. UTC | #6
On Thu, Aug 14, 2014 at 5:45 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> My quick grep audit tells me the viewport check and
> drm_primary_helper_update() are the only places in the core that care.
> The latter is rather dubious anyway since the clipping should be done
> against the adjusted mode and not the user specified mode, so anyone
> using that is already dancing on thin ice.

My understanding has always been that the requested mode is what
userspace plans to feed into the pipe, and the adjusted mode is what
actually lands in the sink. Yeah there's some hilarity in the vblank
code which somehow presumes that the vblank counter works with the
adjusted mode because that's what i915 needs.

It's that fundamental assumption that we break by making the pipe_src
stuff official and which is the part that freaks me out a bit.

> The other drivers are something I would not touch. Given how many places
> we had to frob in i915 I'm somewhat sure I'd not like what I see there
> and then any patch I might cook up would be too half assed to satisfy my
> quality standards anyway.

Yeah, other drivers only need to be audited I think once they start
supporting the pipe_src stuff. But I think the core+helpers should be
able to cope properly.

> As far as always filling the crtc->w,h always goes, I'm not sure that's
> the best idea anyway since we still need the "0 is special" handling.
> Well, we could fill them out, but then we definitely need a flag or
> something to indicate that they came from the mode and not the
> properties, so that we know whether we should overwrite them from
> with {h,v}display during a subsquent modeset or if they should keep
> their current value.

Hm, I guess we can keep that implicit meaning, but then we need a
small helper to get at the crtc viewport, e.g. drm_crtc_viewport_rect
or so. That would also be an excellent place to document this trickery
properly.

Oh and: Such drm changes _really_ must be split out into separate prep
patches cc: dri-devel.
-Daniel
Ville Syrjala Aug. 14, 2014, 4:45 p.m. UTC | #7
On Thu, Aug 14, 2014 at 06:07:44PM +0200, Daniel Vetter wrote:
> On Thu, Aug 14, 2014 at 5:45 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > My quick grep audit tells me the viewport check and
> > drm_primary_helper_update() are the only places in the core that care.
> > The latter is rather dubious anyway since the clipping should be done
> > against the adjusted mode and not the user specified mode, so anyone
> > using that is already dancing on thin ice.
> 
> My understanding has always been that the requested mode is what
> userspace plans to feed into the pipe, and the adjusted mode is what
> actually lands in the sink. Yeah there's some hilarity in the vblank
> code which somehow presumes that the vblank counter works with the
> adjusted mode because that's what i915 needs.

The problem with clipping planes to the user size is that the driver is
free to frob the mode a bit to line it up with hardware constraints. So
what the user requested might be a few pixels off compared to what the
hardware will end up using, and then if you configure the plane
blindly using the coordinates clipped against the user size, the
hardware may get somewhat upset.

> 
> It's that fundamental assumption that we break by making the pipe_src
> stuff official and which is the part that freaks me out a bit.

Yeah there's definitely some dangers with these properties. The biggest
being when one master sets the properties, and then another master which
doesn't know anything about these properties takes over. The result
might be a failed modeset an then the user doesn't see anything.

This is one reason why I'd prefer that we'd maintain the state
per-master. For fbdev the "reset everything to default" trick seems
sufficient but I'm not sure I'd like to that to actual users.

> 
> > The other drivers are something I would not touch. Given how many places
> > we had to frob in i915 I'm somewhat sure I'd not like what I see there
> > and then any patch I might cook up would be too half assed to satisfy my
> > quality standards anyway.
> 
> Yeah, other drivers only need to be audited I think once they start
> supporting the pipe_src stuff. But I think the core+helpers should be
> able to cope properly.
> 
> > As far as always filling the crtc->w,h always goes, I'm not sure that's
> > the best idea anyway since we still need the "0 is special" handling.
> > Well, we could fill them out, but then we definitely need a flag or
> > something to indicate that they came from the mode and not the
> > properties, so that we know whether we should overwrite them from
> > with {h,v}display during a subsquent modeset or if they should keep
> > their current value.
> 
> Hm, I guess we can keep that implicit meaning, but then we need a
> small helper to get at the crtc viewport, e.g. drm_crtc_viewport_rect
> or so. That would also be an excellent place to document this trickery
> properly.

Yeah such small helpers is what I had in mind when suggesting this
originally.

> Oh and: Such drm changes _really_ must be split out into separate prep
> patches cc: dri-devel.

Indeed.
Daniel Vetter Aug. 14, 2014, 5:36 p.m. UTC | #8
On Thu, Aug 14, 2014 at 6:45 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Thu, Aug 14, 2014 at 06:07:44PM +0200, Daniel Vetter wrote:
>> On Thu, Aug 14, 2014 at 5:45 PM, Ville Syrjälä
>> <ville.syrjala@linux.intel.com> wrote:
>> > My quick grep audit tells me the viewport check and
>> > drm_primary_helper_update() are the only places in the core that care.
>> > The latter is rather dubious anyway since the clipping should be done
>> > against the adjusted mode and not the user specified mode, so anyone
>> > using that is already dancing on thin ice.
>>
>> My understanding has always been that the requested mode is what
>> userspace plans to feed into the pipe, and the adjusted mode is what
>> actually lands in the sink. Yeah there's some hilarity in the vblank
>> code which somehow presumes that the vblank counter works with the
>> adjusted mode because that's what i915 needs.
>
> The problem with clipping planes to the user size is that the driver is
> free to frob the mode a bit to line it up with hardware constraints. So
> what the user requested might be a few pixels off compared to what the
> hardware will end up using, and then if you configure the plane
> blindly using the coordinates clipped against the user size, the
> hardware may get somewhat upset.

Hm, I've thought we didn't do that yet, but only frobbed the adjusted
mode to make it fit our requirements for e.g interlaced stuff. I don't
think it would be good if we start doing that since there's no way for
userspace to be aware of the resulting single-pixel border of garbage.

_If_ we need to do that I think we should frob modes when adding them
to the connector mode list.

>> It's that fundamental assumption that we break by making the pipe_src
>> stuff official and which is the part that freaks me out a bit.
>
> Yeah there's definitely some dangers with these properties. The biggest
> being when one master sets the properties, and then another master which
> doesn't know anything about these properties takes over. The result
> might be a failed modeset an then the user doesn't see anything.
>
> This is one reason why I'd prefer that we'd maintain the state
> per-master. For fbdev the "reset everything to default" trick seems
> sufficient but I'm not sure I'd like to that to actual users.

Yeah, this is unsolved territory. Not sure whether attaching the state
to the master should be helpful, or whether we should care at all. For
a generic distro we should boot-up sane-ish, and userspace can always
grab the full property picture and restore that if all else fails. The
fbcon restoring is really just for developers imo.

>> > The other drivers are something I would not touch. Given how many places
>> > we had to frob in i915 I'm somewhat sure I'd not like what I see there
>> > and then any patch I might cook up would be too half assed to satisfy my
>> > quality standards anyway.
>>
>> Yeah, other drivers only need to be audited I think once they start
>> supporting the pipe_src stuff. But I think the core+helpers should be
>> able to cope properly.
>>
>> > As far as always filling the crtc->w,h always goes, I'm not sure that's
>> > the best idea anyway since we still need the "0 is special" handling.
>> > Well, we could fill them out, but then we definitely need a flag or
>> > something to indicate that they came from the mode and not the
>> > properties, so that we know whether we should overwrite them from
>> > with {h,v}display during a subsquent modeset or if they should keep
>> > their current value.
>>
>> Hm, I guess we can keep that implicit meaning, but then we need a
>> small helper to get at the crtc viewport, e.g. drm_crtc_viewport_rect
>> or so. That would also be an excellent place to document this trickery
>> properly.
>
> Yeah such small helpers is what I had in mind when suggesting this
> originally.
>
>> Oh and: Such drm changes _really_ must be split out into separate prep
>> patches cc: dri-devel.
>
> Indeed.

Sounds like we have a rough plan.
-Daniel
Ville Syrjala Aug. 14, 2014, 5:58 p.m. UTC | #9
On Thu, Aug 14, 2014 at 07:36:13PM +0200, Daniel Vetter wrote:
> On Thu, Aug 14, 2014 at 6:45 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Thu, Aug 14, 2014 at 06:07:44PM +0200, Daniel Vetter wrote:
> >> On Thu, Aug 14, 2014 at 5:45 PM, Ville Syrjälä
> >> <ville.syrjala@linux.intel.com> wrote:
> >> > My quick grep audit tells me the viewport check and
> >> > drm_primary_helper_update() are the only places in the core that care.
> >> > The latter is rather dubious anyway since the clipping should be done
> >> > against the adjusted mode and not the user specified mode, so anyone
> >> > using that is already dancing on thin ice.
> >>
> >> My understanding has always been that the requested mode is what
> >> userspace plans to feed into the pipe, and the adjusted mode is what
> >> actually lands in the sink. Yeah there's some hilarity in the vblank
> >> code which somehow presumes that the vblank counter works with the
> >> adjusted mode because that's what i915 needs.
> >
> > The problem with clipping planes to the user size is that the driver is
> > free to frob the mode a bit to line it up with hardware constraints. So
> > what the user requested might be a few pixels off compared to what the
> > hardware will end up using, and then if you configure the plane
> > blindly using the coordinates clipped against the user size, the
> > hardware may get somewhat upset.
> 
> Hm, I've thought we didn't do that yet, but only frobbed the adjusted
> mode to make it fit our requirements for e.g interlaced stuff. I don't
> think it would be good if we start doing that since there's no way for
> userspace to be aware of the resulting single-pixel border of garbage.
> 
> _If_ we need to do that I think we should frob modes when adding them
> to the connector mode list.

Sure but the user can supply any mode, doesn't have to be on any list.
And the only sane rule for the frobbing would be that you can (slightly)
reduce hdisp/vdisp but never expand them so that there will never be any
extra garbage exposed (and the FB might not be big enough anyway). But
even reducing hdisp/vdisp by one pixel can be enough to anger the
hardware if a plane then extends one pixel into the blanking.

This isn't much of a problem for i915 though. The hardware is generally
good enough to not need it. Double wide and (s)dvo/lvds gang mode are
the only exception that comes to mind. Even there we just need to make
pipe src width even, but still that's something we have to account
when clipping planes.

On older hardware there were generally more restrictions eg. some
legacy baggage from VGA days which required horizontal timings to
be multiples of 8. I also "fondly" remember much more magic timing
restrictions in certain pieces hardware which were something close
to "if (foo*bar % this == that) frob else don't". IMO these kinds of
restrictions are too magic to make rejecting the mode an option,
so frobbing is the lesser of two evils.
Daniel Vetter Aug. 14, 2014, 6:33 p.m. UTC | #10
On Thu, Aug 14, 2014 at 7:58 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> Sure but the user can supply any mode, doesn't have to be on any list.
> And the only sane rule for the frobbing would be that you can (slightly)
> reduce hdisp/vdisp but never expand them so that there will never be any
> extra garbage exposed (and the FB might not be big enough anyway). But
> even reducing hdisp/vdisp by one pixel can be enough to anger the
> hardware if a plane then extends one pixel into the blanking.
>
> This isn't much of a problem for i915 though. The hardware is generally
> good enough to not need it. Double wide and (s)dvo/lvds gang mode are
> the only exception that comes to mind. Even there we just need to make
> pipe src width even, but still that's something we have to account
> when clipping planes.
>
> On older hardware there were generally more restrictions eg. some
> legacy baggage from VGA days which required horizontal timings to
> be multiples of 8. I also "fondly" remember much more magic timing
> restrictions in certain pieces hardware which were something close
> to "if (foo*bar % this == that) frob else don't". IMO these kinds of
> restrictions are too magic to make rejecting the mode an option,
> so frobbing is the lesser of two evils.

Imo the mode list we provide should be reasonable for everyone, and if
you start to add your own modes then I expect the user to do that
adjusting for us. Nowadays there should be very few cases where we
don't provide decent mode lists and where it's not a super-special
embedded thing where you need to configure everything yourself anyway.
So I don't think we should ever adjust the input region for a crtc.
-Daniel
Ville Syrjala Aug. 14, 2014, 6:51 p.m. UTC | #11
On Thu, Aug 14, 2014 at 08:33:23PM +0200, Daniel Vetter wrote:
> On Thu, Aug 14, 2014 at 7:58 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > Sure but the user can supply any mode, doesn't have to be on any list.
> > And the only sane rule for the frobbing would be that you can (slightly)
> > reduce hdisp/vdisp but never expand them so that there will never be any
> > extra garbage exposed (and the FB might not be big enough anyway). But
> > even reducing hdisp/vdisp by one pixel can be enough to anger the
> > hardware if a plane then extends one pixel into the blanking.
> >
> > This isn't much of a problem for i915 though. The hardware is generally
> > good enough to not need it. Double wide and (s)dvo/lvds gang mode are
> > the only exception that comes to mind. Even there we just need to make
> > pipe src width even, but still that's something we have to account
> > when clipping planes.
> >
> > On older hardware there were generally more restrictions eg. some
> > legacy baggage from VGA days which required horizontal timings to
> > be multiples of 8. I also "fondly" remember much more magic timing
> > restrictions in certain pieces hardware which were something close
> > to "if (foo*bar % this == that) frob else don't". IMO these kinds of
> > restrictions are too magic to make rejecting the mode an option,
> > so frobbing is the lesser of two evils.
> 
> Imo the mode list we provide should be reasonable for everyone, and if
> you start to add your own modes then I expect the user to do that
> adjusting for us. Nowadays there should be very few cases where we
> don't provide decent mode lists and where it's not a super-special
> embedded thing where you need to configure everything yourself anyway.
> So I don't think we should ever adjust the input region for a crtc.

That's fine for decent hardware. But if/when I write a driver for
old junk I'm probably going to frob no matter what anyone says :)
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f09b752..328efac 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -5169,3 +5169,10 @@  struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
 					   supported_rotations);
 }
 EXPORT_SYMBOL(drm_mode_create_rotation_property);
+
+struct drm_property *drm_mode_create_crtc_size_property(struct drm_device *dev)
+{
+	return drm_property_create_range(dev, 0, "crtc size",
+					   0, UINT_MAX);
+}
+EXPORT_SYMBOL(drm_mode_create_crtc_size_property);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 63d7b8e..6eb1949 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -307,6 +307,13 @@  static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 		struct drm_crtc *crtc = mode_set->crtc;
 		int ret;
 
+		if (dev->mode_config.crtc_size_property) {
+			crtc->crtc_w = crtc->crtc_h = 0;
+			drm_object_property_set_value(&crtc->base,
+				dev->mode_config.crtc_size_property,
+				0);
+		}
+
 		if (crtc->funcs->cursor_set) {
 			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
 			if (ret)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a75d1a0..7c417fc 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10183,6 +10183,12 @@  intel_modeset_pipe_config(struct drm_crtc *crtc,
 	pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay;
 	pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay;
 
+	/* Set the Pipe Src values as per the crtc size property values */
+	if (crtc->crtc_w && crtc->crtc_h) {
+		pipe_config->pipe_src_w = crtc->crtc_w;
+		pipe_config->pipe_src_h = crtc->crtc_h;
+	}
+
 encoder_retry:
 	/* Ensure the port clock defaults are reset when retrying. */
 	pipe_config->port_clock = 0;
@@ -11438,11 +11444,67 @@  out_config:
 	return ret;
 }
 
+static int intel_crtc_set_property(struct drm_crtc *crtc,
+				    struct drm_property *prop,
+				    uint64_t val)
+{
+	struct drm_device *dev = crtc->dev;
+	int ret = -ENOENT;
+
+	if (prop == dev->mode_config.crtc_size_property) {
+		int old_width, old_height;
+		int new_width = (int)((val >> 16) & 0xffff);
+		int new_height = (int)(val & 0xffff);
+		const struct drm_framebuffer *fb = crtc->primary->fb;
+
+		if ((new_width == crtc->crtc_w) &&
+		    (new_height == crtc->crtc_h))
+			return 0;
+
+		/* Check if property is resetted, so just return */
+		if ((new_width == 0) && (new_height) == 0) {
+			crtc->crtc_w = crtc->crtc_h = 0;
+			/* FIXME, Is modeset required here ?. Actually the
+			   current FB may not be compatible with the mode */
+			return 0;
+		} else if ((new_width == 0) || (new_height == 0))
+			return -EINVAL;
+
+		/* Check if the current FB is compatible with new requested
+		   Pipesrc values by the User */
+		if (new_width > fb->width ||
+			new_height > fb->height ||
+			crtc->x > fb->width - new_width ||
+			crtc->y > fb->height - new_height) {
+			DRM_DEBUG_KMS("New Pipe Src values %dx%d is incompatible with current fb size & viewport %ux%u+%d+%d\n",
+			      new_width, new_height, fb->width, fb->height, crtc->x, crtc->y);
+			return -EINVAL;
+		}
+
+		old_width = crtc->crtc_w;
+		old_height = crtc->crtc_h;
+
+		crtc->crtc_w = new_width;
+		crtc->crtc_h = new_height;
+
+		/* Currently do a modeset always, this will also
+		 * enable & configure the Panel fitter accordingly */
+		ret = intel_crtc_restore_mode(crtc);
+		if (ret) {
+			crtc->crtc_w = old_width;
+			crtc->crtc_h = old_height;
+		}
+	}
+
+	return ret;
+}
+
 static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.gamma_set = intel_crtc_gamma_set,
 	.set_config = intel_crtc_set_config,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
+	.set_property = intel_crtc_set_property,
 };
 
 static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -11963,6 +12025,16 @@  static void intel_crtc_init(struct drm_device *dev, int pipe)
 	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
 	WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
+
+	if (!dev->mode_config.crtc_size_property)
+			dev->mode_config.crtc_size_property =
+				drm_mode_create_crtc_size_property(dev);
+
+	if (dev->mode_config.crtc_size_property)
+			drm_object_attach_property(&intel_crtc->base.base,
+				dev->mode_config.crtc_size_property,
+				0);
+
 	return;
 
 fail:
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 0375d75..b409003 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -354,6 +354,11 @@  struct drm_crtc {
 	bool invert_dimensions;
 
 	int x, y;
+
+	/* Gets set only through the crtc_size property */
+	int crtc_w;
+	int crtc_h;
+
 	const struct drm_crtc_funcs *funcs;
 
 	/* CRTC gamma size for reporting to userspace */
@@ -826,6 +831,7 @@  struct drm_mode_config {
 	struct drm_property *path_property;
 	struct drm_property *plane_type_property;
 	struct drm_property *rotation_property;
+	struct drm_property *crtc_size_property;
 
 	/* DVI-I properties */
 	struct drm_property *dvi_i_subconnector_property;
@@ -1137,6 +1143,7 @@  extern int drm_format_vert_chroma_subsampling(uint32_t format);
 extern const char *drm_get_format_name(uint32_t format);
 extern struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
 							      unsigned int supported_rotations);
+extern struct drm_property *drm_mode_create_crtc_size_property(struct drm_device *dev);
 extern unsigned int drm_rotation_simplify(unsigned int rotation,
 					  unsigned int supported_rotations);