Number screen mode subsitutions
David J. Ruck (33) 1635 posts |
I’ve been using my new found time to go back and look at some old non desk graphical programs. About half run under !GraphTask, but the other half use direct screen addressing, and invariably MODE 13 (320×256 64 colours). On my ARMx6 Mini.m and Iyonix with a 1440p monitor, these dont work correctly as a 640 wide pixel mode is being substituted instead. So I decided to look in to what is happening. Using OS_ReadModeVariables for all numbered modes, things look pretty much like they did back in RISC OS 3.X days, except for the pixel doubling of 160 wide modes, which is understandable, and agrees with the ROOL’s table However going in to the mode and reading what you’ve actually got using OS_ReadVduVariables is another story. The number of colours is bumped up as the Mini.m supports a minimum of 4 bpp, and the Iyonix a minimum of 8 bpp. Substitution of odd shaped ones such as 16,17,23,24 and 37-40 is rounded up to the nearest resolution in the MDF which is OK. However what happens to 320×256 modes if that resolution is not in the MDF is a bit odd, and I think wrong. On the Mini.m running RISC OS 5.27 with a 1440p monitor, 320×256 not defined (monitor can’t go that low):- Mode Resolution BPP Pixel Double Resolution BPP ---- ---------- --- ------------ ---------- --- 0 640x256 1 640x256 4* Different 1 320x256 2 640x350 * 4* Different 2 160x256 4 Yes Yes 320x350 * 4 Different 3 640x250 2 640x350 * 4* Different 4 320x256 1 Yes Yes 320x256 4* Different 5 160x256 2 Yes Yes 320x350 * 4* Different 6 320x250 2 640x350 * 4* Different 7 640x500 8 720x576 * 8 Different 8 640x256 2 640x256 4* Different 9 320x256 4 640x350 * 4 Different 10 160x256 8 Yes Yes 320x350 * 8 Different 11 640x250 2 640x350 * 4* Different 12 640x256 4 640x256 4 13 320x256 8 640x350 * 8 Different 14 640x250 4 640x350 * 4 Different 15 640x256 8 640x256 8 16 1056x256 4 1280x1024 * 4 Different 17 1056x250 4 1280x1024 * 4 Different 18 640x512 1 640x512 4* Different 19 640x512 2 640x512 4* Different 20 640x512 4 640x512 4 21 640x512 8 640x512 8 22 768x288 4 800x600 * 4 Different 23 1152x896 1 1280x1024 * 4* Different 24 1056x256 8 1280x1024 * 8 Different 25 640x480 1 640x480 4* Different 26 640x480 2 640x480 4* Different 27 640x480 4 640x480 4 28 640x480 8 640x480 8 29 800x600 1 800x600 4* Different 30 800x600 2 800x600 4* Different 31 800x600 4 800x600 4 32 800x600 8 800x600 8 33 768x288 1 800x600 * 4* Different 34 768x288 2 800x600 * 4* Different 35 768x288 4 800x600 * 4 Different 36 768x288 8 800x600 * 8 Different 37 896x352 1 1024x768 * 4* Different 38 896x352 2 1024x768 * 4* Different 39 896x352 4 1024x768 * 4 Different 40 896x352 8 1024x768 * 8 Different 41 640x352 1 640x400 * 4* Different 42 640x352 2 640x400 * 4* Different 43 640x352 4 640x400 * 4 Different 44 640x200 1 640x350 * 4* Different 45 640x200 2 640x350 * 4* Different 46 640x200 4 640x350 * 4 Different 47 360x480 8 640x480 * 8 Different 48 320x480 4 320x480 4 49 320x480 8 320x480 8 50 320x240 1 640x350 * 4* Different 51 320x240 2 640x350 * 4* Different 52 320x240 4 640x350 * 4 Different 53 320x240 8 640x350 * 8 Different Instead of substituting 640×256 for the 320×256 modes which I think would be the logical choice, its picked a 640 wide pixel mode with the closet vertical resolution of 350, which leads to empty space at the bottom of the screen. If I comment out 640×350, it uses the next one of 640×400, and if I comment out that one 640×480. I obviously don’t want to get rid of that as the I can’t use MODE 28 etc. Incidentally 320×480 is defined and used for modes 48 & 49, but this isn’t considered as a substitute for 320×256. It would still give a blank space at the bottom of the screen, but would have the correct horizontal resolution for the direct screen addressing code. Can anyone explain the logic behind the mode substitutions, and whether they can be overridden? |
Jeffrey Lee (213) 6048 posts |
You’re in luck, because the mode substitution logic was one of the things I changed recently (“recently” in glacial terms; it looks like it was actually a year and a half ago) TL;DR is that the old logic was convoluted and not fit for purpose. The new logic (which is what you’re experiencing) isn’t perfect either, but it’s less likely to do silly things, and because it’s all implemented within Service_ModeTranslation handlers it should be possible to replace it with custom logic where necessary. If a numbered mode can’t be directly supported, then the kernel will call Service_ModeTranslation to see if there’s an alternative available. The default Service_ModeTranslation implementations will search for a replacement as follows:
For the kernel’s implementation of Service_ModeTranslation (which will only be used if the current monitor type is one of the monitor types for which the kernel has a builtin set of modes), the only alternate resolution that it will try is the standard resolution for the monitor type (640×480, 640×256, or 640×200). ScreenMode’s implementation (which is used for MDF/EDID monitor types, i.e. your case) is slightly better, in that it will run through a list of industry-standard resolutions:
Since 640×350 is the lowest resolution in that list, that explains why your 320×256 mode is being upgraded to that resolution. For each alternate mode tried, it will also repeat as many of the above steps as sensible – i.e. downgrading double-pixel to normal, and different BPPs. Another thing the Service_ModeTranslation implementations do is try to preserve any other special features like gap modes & teletext (which would have been completely lost under the old system). |
Andrew Rawnsley (492) 1445 posts |
For clarity, the reason why the low resolutions aren’t in the ARMX6/iMX6/minim MDF is that (in line with HDMI specs) modern GPUs tend to have a lower limit to their clock of approx 25kHz (I think that’s correct – 25000 in the MDF). Some low-ish modes can be coaxed into working by altering their timings, but once you get down to the lower numbered modes, I failed to come up with modes which would display, pretty much regardless of monitor. Realistically this needs someone to come up with some kind of “numbered mode emulator” which handles low res modes (which will typically be numbered, with the possible exception of 480×352 from the RiscPC MDF). It could either letter-box (or rather, blank-frame) the mode in (say) 640×480, or allow scaling methods (basic integer scaling seems back in fashion). The slight fly in the ointment is that not all GPUs do all the low colour depths. iMX6 for example isn’t fond of 16 colours, whilst for a long time Titanium didn’t like 256 (although Rob came up with a clever workaround for that). As such, the best solution would have to emulate colour depth as well, which certainly adds complexity :( |
Jeffrey Lee (213) 6048 posts |
25MHz – the MDF specifies the frequency in units of kHz. I would like to see some more improvements to our handling of low-res/low-colour modes, but so far the relevant items haven’t found their way to the top of my todo list. |
Steffen Huber (91) 1953 posts |
HDMI can transport screen modes like 480i (60 Hz, NTSC) or 576i (50 Hz, PAL) without problems, according to Wikipedia it employs “a pixel repetition scheme”, but many modern GPUs of course don’t like the idea of interlace modes at all.
Didn’t Aemulor Pro have some low bpp emulation, specially for Sibelius on IYONIX pc? Rendering into an off-screen bitmap and blitting it to whatever real resolution/colour depth mode is active should have sufficient performance on modern machines, no? I’m sure Nemo, Jeffrey and Adrian already prototyped such stuff. |
Jeffrey Lee (213) 6048 posts |
Pixel repetition can be used independently of interlace. IIRC it’s basically horizontal integer upscaling of the image (ideally performed by the GPU, so software doesn’t need to access the framebuffer any differently), but the display is also notified of the scaling so that it can display the image at the correct aspect ratio. As well as allowing low pixel rate modes to be used, it can also be used to increase the amount of bandwidth available for other data like audio. But it is a HDMI feature, so it does require the link to be operating in HDMI mode so that the right metadata can be sent with each frame. I think we can support this for the iMX6 (yay, publicly documented HDMI block) and the Pi (the hdmi_timings command which we use for giving the GPU mode timings has a “pixel_rep” parameter). It just requires some thought on how to integrate it into the video stack (e.g. is it used automatically, or must MDF entries explicitly state they want it to be used?)
Yes.
Yes. I’ve got a prototype GraphicsV driver that sits inbetween the OS and the real driver. But there’s a fair amount of work required to turn that prototype into something production-ready (mainly to do with wrestling control of VRAM memory mapping away from the kernel and letting drivers manage it themselves) |
David J. Ruck (33) 1635 posts |
Andrew wrote:
Yes, I hit that. I did come up with a working’ish 320×256 mode by taking 640×256 and increasing the boarders by 160 on each side. This displays stably on my AOC 1440p unless the mouse pointer is enabled and goes off the edges of the screen, in which cases it blanks everything! Most of the old MODE13 programs I want to run (and couldn’t fathom the direct screen addressing assembler code, to convert it to MODE21) don’t have the mouse pointer on are fine.
I’d like to extend !GrasphTask in to do this, it would involve quite a substantial change to redirect output to a sprite while the task window task is running (as opposed to only in the handler task when it is processing the VDU stream), and intercepting a lot of SWIs to make the program think it was running full screen.
I was pleasantly surprised the the iMx6 supported 16 colour modes, as the Iyonix didn’t which broke a lot of old stuff. I don’t think anything has missed the old 1 and 2 colour modes, as they just get a 16 (or 256) colour mode and the right palette, so VDU stuff works as is – they don’t do any direct screen addressing. |