View Single Post
Old 07-02-2015, 06:44 AM   #33
frostschutz
Linux User
frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.frostschutz ought to be getting tired of karma fortunes by now.
 
frostschutz's Avatar
 
Posts: 2,282
Karma: 6123806
Join Date: Sep 2010
Location: Heidelberg, Germany
Device: none
Sample program:

Code:
int query_rotate()
{
    int r;
    FILE * f = fopen("/sys/class/graphics/fb0/rotate", "r");
    r = fgetc(f)-'0';
    fclose(f);
    return r;
}

for(i=5; i--; )
{
    ioctl(fb0, FBIOGET_VSCREENINFO, &screen);
    printf("FBIOGET_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());

    ioctl(fb0, FBIOPUT_VSCREENINFO, &screen);
    printf("FBIOPUT_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());
}
(the query_rotate to verify what /sys/class/graphics/fb0/rotate reports is identical to what the ioctl reports, that seems to be the case)

Session on the H2O:

Code:
# reboot to get clean initial state
...
# ./flipper
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
# cat /sys/class/graphics/fb0/rotate > /sys/class/graphics/fb0/rotate
# cat /sys/class/graphics/fb0/rotate > /sys/class/graphics/fb0/rotate
# ./flipper
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOGET_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOGET_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
So somehow writing to /sys/class/graphics/fb0/rotate "dirties" it and from then on it starts flipping the rotation around and suddenly you FBIOGET sometimes 1 sometimes 3 and you start drawing things upside down. So on one and same device you get two separate possible behaviours: it might flip the rotation or it might not. Confusing!

As a result, if you use FBIOPUT_VSCREENINFO, you have to use it twice in order to make sure the rotation is what you intended.

Code:
for(i=5; i--; )
{
    ioctl(fb0, FBIOGET_VSCREENINFO, &screen);
    printf("FBIOGET_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());

    ioctl(fb0, FBIOPUT_VSCREENINFO, &screen);
    printf("FBIOPUT_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());
    // doubled the FBIOPUT
    ioctl(fb0, FBIOPUT_VSCREENINFO, &screen);
    printf("FBIOPUT_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());
}
Code:
# reboot
...
# ./doubleflipper
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
# cat /sys/class/graphics/fb0/rotate > /sys/class/graphics/fb0/rotate
# cat /sys/class/graphics/fb0/rotate > /sys/class/graphics/fb0/rotate
# ./doubleflipper
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 3 (3)
FBIOPUT_VSCREENINFO 1 (1)
In this case dirty or not, GET always gets 1 and not either 1 or 3 as before.

That's not what pickel does, however. It calls get twice, put once.

Code:
ioctl(3, FBIOGET_VSCREENINFO, 0x7efb9820) = 0
ioctl(3, FBIOPUT_VSCREENINFO, 0x7efb9820) = 0
ioctl(3, FBIOGET_VSCREENINFO, 0x7efb9820) = 0
Also the flipper starts flipping after pickel even if the state was clean before.

Code:
# reboot
...
# ./doubleflipper
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
# /usr/local/Kobo/pickel showpic < /dev/urandom
# ./doubleflipper
FBIOGET_VSCREENINFO 2 (2)
FBIOPUT_VSCREENINFO 0 (0)
FBIOPUT_VSCREENINFO 2 (2)
(It's 2 now because pickel rotated the screen)

Since pickel is used during boot already, it's unclear to me how nickel afterwards starts out in a "clean" state and how using pickel again makes it start flipping using just FBIOGET/PUT when my own program using the same syscalls does not have the same effect.

It probably puts something into the vscreeninfo struct, but what? Or it just can handle either case on its own? What am I missing?

EDIT:

What I'm missing of course, is that pickel itself flips the rotation.

Code:
for(i=5; i--; )
{
    ioctl(fb0, FBIOGET_VSCREENINFO, &screen);
    printf("FBIOGET_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());

    screen.rotate^=0x2; // flip

    ioctl(fb0, FBIOPUT_VSCREENINFO, &screen);
    printf("FBIOPUT_VSCREENINFO %d (%d)\n", screen.rotate, query_rotate());
}
Apparently flipping the rotation does the dirtying (?) so before and after looks the same:

Code:
# reboot
...
# ./pngshow maze.png 
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
# cat /sys/class/graphics/fb0/rotate > /sys/class/graphics/fb0/rotate
# cat /sys/class/graphics/fb0/rotate > /sys/class/graphics/fb0/rotate
# ./pngshow maze.png 
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
FBIOGET_VSCREENINFO 1 (1)
FBIOPUT_VSCREENINFO 1 (1)
That doesn't help me much though. I wanted to be able to know how to draw stuff correctly without ever touching the rotation, so that other running processes (nickel in particular) can still draw their own stuff without knowing the fb was modified in between.

This thing is giving me headaches.

Edit: I ended up with this framebuffer rotation hack for now:

Code:
// get rotation
ioctl(fb0, FBIOGET_VSCREENINFO, &screen);
// remember rotation
rotate = screen.rotate;
// flip rotation
screen.rotate ^= 0x2;
// put rotation: some devices flip on put, some don't
ioctl(fb0, FBIOPUT_VSCREENINFO, &screen);
// check if it did not flip
if(rotate != screen.rotate)
{
    // restore original rotation
    screen.rotate = rotate;
    // put original rotation
    ioctl(fb0, FBIOPUT_VSCREENINFO, &screen);
    // flip rotation
    screen.rotate ^= 0x2;
}
// now screen.rotate means the same thing on all devices
// regardless whether they flip or not
It's racy so better to do this once and remember.

Last edited by frostschutz; 07-02-2015 at 08:59 AM.
frostschutz is offline   Reply With Quote