A Couple Quick Dev Questions


Mudi

You're pushing your luck little man
Joined
Jan 25, 2006
Messages
815
Website
mudiweb.com
How can you determine the current framebuffer mode? I want to be able to take a screenshot by directly accessing the framebuffer then convert it to 16-bit 565 mode, but I need to know the mode (and the palette in the case of 8-bit) to do this.

Is there a way to suspend the current foreground process? I can suspend sterm successfully using kill(0,SIGTSTP), but oddly I can't get any other apps to stop it seems...
 
SDL apps probably ignore the suspend signal. Try pressing ctl-z at the term.

Anyway, you can either inspect the registers manually or start reading the docs for the framebuffer devices. There should be an ioctl you can use to get the current mode.
 
Somewhat new plan... determine the pid of the foreground app and send the uningorable SIGSTOP to it. Any easy way to determine the foreground app? I can't find any easy way to do it...
 
Asking /dev/fb is pointless as (upto the latest 1.4 firmware) it only supports 16bit.
The definitive way is to read the display registers, you'll need to mmap the registers to get them into your app's memory space, they physically start at 0xC000 0000 and are 16bit.
Register 0x28DA (MLC_STL_CNTL) holds the bit-depth,
0x290E, 0x2910 and 0x2912, 0x2814 hold the physical addresses of the start of the screen, both pairs typically hold the same value.
To read the 8bit pallette, write 0 to register 0x2958, and then read 0x295A twice (first time gives green:blue, second gives red) 256 times, colours are 8bit values.
Code:
unsigned long dev_mem;
volitile unsigned short *reg;

dev_mem = open("/dev/mem",   O_RDWR);
reg = (unsigned short*)mmap(0, 0x10000,   PROT_READ|PROT_WRITE, MAP_SHARED, dev_mem, 0xC0000000);

// get bpp, 4bit = 0, 8bit = 1, 16bit = 2, 24bit = 3
bpp = (reg[0x28DA>>1]  >> 9) & 0x3;

// read colours
reg[0x2958>>1] = 0;
for( i=0; i<256; i++) {
  col_gb = reg[0x295A>>1];
  colours[i].green = col_gb >> 8;
  colours[i].blue = col_gb & 0xFF;
  colours[i].red = reg[0x295A>>1];
}

screen_start = (reg[0x2910>>1] << 16) + reg[0x290E]);
You'll have to mmap the screen memory to read it.
There's also a load of stuff that the hardware can do that won't appear from a simple frame grab (YUV overlays, OSD, regions) but there's not many programs that take advantage of these (yet ;) )

Would people be interested in having an SDL function that can return screen-grabs? I'm having a few days rest from programming because my fingers are in pain when I type, but I'll add it to my (ever growing) to-do list if anyone wants it.
 
I'm not too concerned for the screen-grab to be 1:1 including overlays and such, I just want to be able to return the old framebuffer to the framebuffer memory after my program is finished with what it's doing. Also, I'd like to change the screen mode to 16-bit 565 if it isn't already there... when I drew directly to the framebuffer and the screen was in 8-bit palletted mode, I got behavior that was consistent with the framebuffer acting like it was in 8-bit mode (drawing every other line, wrong color). So I'd like to convert a screengrab of the current framebuffer to the current screen mode to act as a background... and since it would only change this stuff in case of 8-bit mode (or a really weird 16-bit format), I doubt YUV overlays will be any trouble at all.

An SDL function would be cool, but for this program at least I'm avoiding SDL and accessing hardware through Linux /dev stuff instead...

As for the foreground process:
http://www.opengroup.org/onlinepubs/007908.../tcgetpgrp.html

Could I feed this a file descriptor to /dev/fb/0? Or does it require a TTY? (sorry, no time to expiriment at the moment, got homework to do... if this hasn't been answered by sometime tomorrow, chances are I've already tried it)

Hmm... wait... is there a way to send a signal to a process group other than an application's own? Grr...
 
Some programs may use a framebuffer that is wider than the screen (e.g. for hardware scrolling, doublebuffering), register 0x290C holds the number of bytes to add to get to the next line, so far a normal framebuffer it would either 320 for 8bit, or 640 for 16bit.
/dev/fb alone is crippled, it has limited knowledge of the display capabilities. There's extra stuff in /dev/vpp (video post-process), but (especially for games) a lot of developers will just modify the hardware directly.
 
Mudi posted on Apr 16 2006 at 10:01 PM said:
I'm not too concerned for the screen-grab to be 1:1 including overlays and such, I just want to be able to return the old framebuffer to the framebuffer memory after my program is finished with what it's doing. Also, I'd like to change the screen mode to 16-bit 565 if it isn't already there... when I drew directly to the framebuffer and the screen was in 8-bit palletted mode, I got behavior that was consistent with the framebuffer acting like it was in 8-bit mode (drawing every other line, wrong color). So I'd like to convert a screengrab of the current framebuffer to the current screen mode to act as a background... and since it would only change this stuff in case of 8-bit mode (or a really weird 16-bit format), I doubt YUV overlays will be any trouble at all.

An SDL function would be cool, but for this program at least I'm avoiding SDL and accessing hardware through Linux /dev stuff instead...
If I understand correctly, the program you're working on should interrupt the one that currently is using the display, then grab all the display related info, take over the display yourself, do whatever it is you're doing, then put everything back and restart the user's program.

If you can figure out the process stuff it seems doable. After stopping the user's program I'd just grab all potentially relevant MMSP2 registers and store them away. I'd also store all the physical memory for the "standard" frame buffer (the physical address for this is available somewhere, I don't remember it off hand). Then use the standard frame buffer for your display and restore the memory when you're done. It doesn't matter how the user's program is using video.

From your description I get the impression that you want to initialize your own private buffer with the contents of the screen that is currently visible (perhaps because you want your program to look like a popup menu or overlay of some kind). To do that you'll have to interpret the registers properly and it's not simple to handle all the cases. There may be hardware scaling going on for example, in which case you'll have to sample the memory to reconstruct a plausible idea of what was on the screen. I wrote a little screengrab utility for a review site that I'm slowly working on (www.gp2xgamer.com); it tries to deal with these issues and works most of the time, but programs do odd things with the video sometimes!
 
Last edited by a moderator:
Well I figure the occasional messed up background isn't going to be a significant problem, I just want it to work "most of the time", I guess.

I've written something that finds the process accessing "/dev/fb/0", but I'd like to find some way to do this without linking the gigantic glibc, which is the only quick way I could find to find the target of a symbolic link [realpath()]. Any ideas?

Probably my best option for the background right now is just don't mess with it if the registers are set to the default (and hopefully most common) settings, but change settings and replace it with something else if necessary. And yes, the plan is to store the old framebuffer and put it back when I return control to the original program.
 
Back
Top