Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for DRM/KMS orientation parameter #13

Open
fifteenhex opened this issue Feb 9, 2022 · 15 comments
Open

Support for DRM/KMS orientation parameter #13

fifteenhex opened this issue Feb 9, 2022 · 15 comments

Comments

@fifteenhex
Copy link
Contributor

fifteenhex commented Feb 9, 2022

Hi,

Sorry for the flood of issues.

I have a DRM/KMS driver, one of the machines that uses it has the screen mounted upside down. There is hardware to do rotation of a framebuffer but not on the framebuffer as it as being scanned out (i.e. it needs to be rotated into a second buffer). I was going to do this in the kernel driver itself. But was told "do it in userspace" (https://lore.kernel.org/all/CAFr9PXnig9YfnwSzMg5UPm3UtAsEAQT_xVheBbLppiU45mc_QQ@mail.gmail.com/).

I think I could hack up SDL1 to do the rotation before flip but SDL2 doesn't work with the DRM/KMS driver because there is no GPU to do the drawing (and mesa is massive etc).

So my plan is to fix the issue at the directfb2 level and then build SDL1/2 on top of directfb2.

Scanning through the current code I can't see the drmkms system consuming the orientation. Do you think it would be much work to have it parse it and the rotate the framebuffer before sending it to be displayed?

@caramelli
Copy link
Contributor

caramelli commented Feb 9, 2022

Hardware with a 2D blitter, this seems suitable for DirectFB :-)

Just to make sure I understand you correctly about rotation:

  • "I could hack up SDL1": you propose to hack the Linux Framebuffer backend available in SDL1
  • as the Linux Framebuffer backend was removed in SDL2, you are thinking of using the DRM/KMS backend with SDL2, but yes the implementation in SDL2 requires 3D GPU stuff like gbm...

So your idea is to use DirectFB backend available in both SDL1 and SDL2

In SDL/src/video/directfb code, maybe you can call SetBlittingFlags() with DSBLIT_ROTATE90, DSBLIT_ROTATE180, DSBLIT_FLIP_VERTICAL, ... You can already experiment it (software fallbacks in DirectFB will be used).

To take advantage of your 2D accelerator, you can write a specific DirectFB module for it (GFX driver module).
I plan to add dedicated repositories for this (as this is hardware platform specific), but in the meantime you can take a look at the legacy gfxdrivers as an example: https://github.com/caramelli/DirectFB2/tree/directfb-1.8/gfxdrivers
This is the tricky part of DirectFB, but probably one of the most interesting part.

But I also understand that you would like to do something simple directly in the drmkms system module: I don't know if it's easy to make it work but you can try.

@fifteenhex
Copy link
Contributor Author

Hardware with a 2D blitter, this seems suitable for DirectFB :-)

I think so too. It can do rotation, line drawing, fills etc. Very classic 2D hardware

Just to make sure I understand you correctly about rotation:

  • "I could hack up SDL1": you propose to hack the Linux Framebuffer backend available in SDL1
  • as the Linux Framebuffer backend was removed in SDL2, you are thinking of using the DRM/KMS backend with SDL2, but yes the implementation in SDL2 requires 3D GPU stuff like gbm...

So your idea is to use DirectFB backend available in both SDL1 and SDL2

Yes. I want to fix the issue in one place. DirectFB also has the bonus that it doubles up as a window manager multiple apps could be running at the same time. The machine that has the screen upside down is a gameboy shaped emulator machine.
For that it would be nice to start an SDL app like an emulator but still have the UI running at the same time.

In SDL/src/video/directfb code, maybe you can call SetBlittingFlags() with
DSBLIT_ROTATE90, DSBLIT_ROTATE180, DSBLIT_FLIP_VERTICAL, ...
You can already experiment it (software fallbacks in DirectFB will be used).

Interesting. Thanks for the hint.

To take advantage of your 2D accelerator, you can write a specific DirectFB module for it
(GFX driver module). I plan to add dedicated repositories for this (as this is hardware platform specific),
but in the meantime you can take a look at the legacy gfxdrivers as an example: >https://github.com/caramelli/DirectFB2/tree/directfb-1.8/gfxdrivers This is the tricky part of DirectFB,
but probably one of the most interesting part.

That's the idea. I have a kernel driver that exports a char device to control the blitter. I'm writing a little userspace library to operate it. Then DirectFB would call into the library to use the hardware.

But I also understand that you would like to do something simple directly in the
drmkms system module: I don't know if it's easy to make it work but you can try.

This is mostly to fix up the rotation in one place. If the drmkms system module knows about the rotated screen and does what is needed to make apps appear correctly the whole system is a lot easier to put together. If the drmkms system level can also call the 2D blitter to do the rotation the CPU overhead is low and everything above DirectFB should just work.

@fifteenhex
Copy link
Contributor Author

For reference here is the target SoC running DirectFB2 and SDL2 for ScummVM.
https://twitter.com/linux_chenxing/status/1492708033763635202

@fifteenhex
Copy link
Contributor Author

I've made some progress on this. The drmkms system can now probe the display orientation from kernel side.
Now working on finding the best/right place to apply the rotation.

@fifteenhex
Copy link
Contributor Author

Pretty close on this now. DFB supports rotation internally so it can already handle flipping around the inputs etc.
There is already a rotate configuration option that should flip everything but it doesn't currently work as where the effective rotation is calculated (the rotation of the layer after applying the rotation of the surface) the rotation is cancelled out as currently both sides have the same value. So for 180 degrees which should flip the screen the layer has 180 and the surface has 180 which means the result is 0 and no flip happens. I guess that the surface rotation should be happening in hardware (I think the linux framebuffer layer used to have call backs for it..) and it's thinking: The hardware is already scanning out flipped, without flipping during blit of the layer it's correct.

@caramelli
Copy link
Contributor

Yes I forgot this rotate configuration option. So if you set rotate=180 in the directfbrc config file, you probably get the expected result.
But to use the hardware capabilities of your platform, I still ask myself the question of using a dedicated module defined with the DFB_GRAPHICS_DRIVER() macro and which implements certain GraphicsDeviceFuncs functions such as SetState(), Blit(), ... Then, when setting rotate=180, the hardware capabilities should be used via the Blit() function of this dedicated module.

@fifteenhex
Copy link
Contributor Author

Yes I forgot this rotate configuration option. So if you set rotate=180 in the directfbrc config file, you probably get the expected result.

I thought that too but it currently doesn't work because the calculation for the blitting flags comes up with 0 degrees rotation.
I have it working now by commenting that out so it always applies the rotation (fifteenhex@c8c5044). I have the required rotation coming from the kernel now too.. so there just need to be a little bit of extra code that uses the rotation value from the kernel and it'll work transparently.
I'm sure it must have worked some time in the past because the translation of the mouse point seems to work.

Then, when setting rotate=180, the hardware capabilities should be used via the Blit() function of this dedicated module.

This is certainly needed. With a 640x480 screen the overhead of rotation seems to be ok. But with a 1024x600 screen the CPU usage of my test app (chocolate doom) goes from 70% to 90%.

@caramelli
Copy link
Contributor

When setting rotate=180, I can see that the image is flipped vertically and I have rotation = surface->rotation = 180, so after rotation -= surface->rotation => rotation = 0 in this case.
In the dfb_layer_context_allocate_surface() function, we can see: surface->rotation = (context->rotation == 180) ? 180 : 0;

@fifteenhex
Copy link
Contributor Author

When setting rotate=180, I can see that the image is flipped vertically and I have rotation = surface->rotation = 180, so after rotation -= surface->rotation => rotation = 0 in this case. In the dfb_layer_context_allocate_surface() function, we can see: surface->rotation = (context->rotation == 180) ? 180 : 0;

Is that with the fbdev backend? maybe this is just a problem with drmkms?

@caramelli
Copy link
Contributor

caramelli commented Feb 19, 2022

Yes you're right, I can see that the image is flipped vertically only with the fbdev system. We have different behaviors:

  • fbdev: dfb_layer_region_flip_update() calls back_to_front_copy() => flags |= DSBLIT_ROTATE180
  • drmkms: dfb_layer_region_flip_update() is called with DSFLIP_UPDATE => goto update_only => UpdateRegion() => drmkmsPrimaryUpdateRegion()

In drmkmsPrimaryUpdateRegion(), we have the surface->rotation information.
On my side, I still don't know how to make rotate=180 config option work with drmkms...

@fifteenhex
Copy link
Contributor Author

fifteenhex commented Feb 20, 2022

In drmkmsPrimaryUpdateRegion(), we have the surface->rotation information.
On my side, I still don't know how to make rotate=180 config option work with drmkms...

I guess that surface->rotation should be the physical rotation of the surface (normally 0) but it's picking up the desired rotation.
I think surface->rotation is where I should be plugging in the rotation probed from the kernel.

Edit:
surface->rotation should be the rotation applied at scanout. i.e. if the hardware can do 180 flip it should be 180 so the desired rotation cancels out. So surface->rotation should be 0 so that the desired rotation is applied in software.

@fifteenhex
Copy link
Contributor Author

Found something interesting:

  • For me on QEMU with the fbdev backend 180 flip doesn't work.
  • 90/270 rotations work on both fbdev and drmkms backends.

@caramelli
Copy link
Contributor

If you test for example with df_andi, you may also have different behaviors when using the force-windowed option:

df_andi --dfb:force-windowed,scaled=x (width and height can be set to screen resolution)

Yes, it would be nice to clarify (and possibly fix) all this, differences between 180 and 90/270, possible confusion between layer rotation (the rotate parameter) and surface rotation. And I would like to understand the different behaviors I get between fbdev and drmkms.

@caramelli
Copy link
Contributor

Between fbdev and drmkms, dfb_surface_flip_buffers() may behave differently. In my case:

  • fbdev : back buffer policy SYSTEMONLY != front buffer policy VIDEOONLY
  • drmkms : back buffer policy = front buffer policy (VIDEOONLY)

It actually depends on the result of fbdevPrimaryTestRegion() / drmkmsPrimaryTestRegion() when creating the surface.
In my case, fbdevPrimaryTestRegion() failed for a double-buffered surface while drmkmsPrimaryTestRegion() passed.

Hope we can clarify the correct behavior for layer rotation for all cases.

@fifteenhex
Copy link
Contributor Author

Now that I've got hardware rotation running I've started looking at this again.
I've added the changes I have for passing the rotation of the screen via DRM/KMS to DFB2 here:
#73

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants