-
-
Notifications
You must be signed in to change notification settings - Fork 148
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
Add overscan (border) support #1792
Comments
FYI: My Commander Keen reimplementation project supports this, albeit emulating only the VGA variant. The border size we use for VGA 320×200 is:
The latter can cause a few problems at 1× scale, but that can be worked around with some care. |
If it's a vote, I vote YES for this one! I really dig this old stuff. I like to keep the border smaller though... like with Commodore 64 Emulators too. And, If you play Alley Cat, use the booter version or you won't get the awesome PCJr music. I think Archon too had a color-changing border. |
Yeah I'll add this at some point, but it's relatively low on my priority list. Ideally, I'd like to do it after @GranMinigun's pipeline refactoring stuff; easier than fighting the current mess.
With my proposed solution you could set the exact desired border size — even just a few pixels if that's what you want. I see very little point in mimicking the monitor hardware exactly for this feature like one of the guys on Vogons tried in his super complex patch I linked above. |
You seem to be a bit of an expert in all things PCjr, perhaps you'd like to help with this Wiki page about games that have the best video and/or sound on the PCjr or the Tandy: It's work in progress, so don't go crazy yet, but I'll ping you when I think it's ready. I'm gonna include a lot of other games from another source and reformat the whole thing. |
The easiest way to show overscan colour would be to set clear colour for both texture and GL outputs. Of course, that will paint the whole area around actual image, but I guess that's still better than nothing? Couple with limited viewport size to also get top and bottom borders. Specific border size is a bit more involved, but should be trivial enough still ( Does DOSBox currently expose any overscan controls? That is, is it possible to get the overscan colour and know when it was set? |
Yeah there are some solutions that seem easy but have some drawbacks. E.g. when the viewport resolution is set to 960x720 (that's typically what I use on my 1920x1080 screen), I really don't want the whole black area in fullscreen to change colour. For example, when I use FastTracker II, in edit mode the border becomes red. You're frequently in edit mode, like 50% of the time when writing music. Having to stare at a 50% red screen is a no-go (FT II uses 640x480, so there would be lots of blank space in fullscreen with the typical 2x scaling). Another consideration, I definitely want to border to be processed by the shaders as well (probably that will happen automatically even with setting the clear colour). There's two reasons for this:
If I were to implement this now, I'd do it like this probably:
The It's easier to illustrate the windowresolution == viewport_resolution — border fully clippedwindowresolution > viewport_resolution — border not clippedSame scenario in fullscreen mode. windowresolution > viewport_resolution (vertically only) — border is not clipped vertically, but is clipped horizontallyvariation of the above — the border is not clipped horizontally, but is clipped a little bit vertically because it doesn't fit into the windowAnyway, I think the images and my above description should make it clear how I envisage this to work. In the end, I think it will be easiest if I implement it 😄 I'm quite convinced this is the best way to implement border support 😄
You can read it from certain CGA/EGA/VGA registers — it is easy to get that info. |
Not the case, because clearing backbuffer doesn't equal drawing to it with a shader.
Great. Then it's only a matter of improving rendering pipeline. |
Yeah, so everything what I wrote in my long post above stands then. |
Personally, I suspect the most accurate way to handle this is to have the VGA code just generate a larger image with the border included. The exact size of the border could easily depend on which video card is being emulated. (Though, as mentioned, you'd need to have the VGA code do line-doubling for some modes, which could cause problems for some setups. You could just disable line doubling and round the border size if scaling is disabled / the window is too small, though.) The way I handle it in my Commander Keen project is by using the clear colour, but rendering to a texture (which then undergoes the final scaling). But I was rendering-to-texture as part of my two-stage scaling process anyway, so it has no extra cost: I suspect that DOSBox doesn't, so this might be slower. Regardless, it's probably worth looking at @NY00123's old patches on Vogons. As mentioned, I think having the overscan border be a part of the VGA code is probably the way to go about it, so I'd probably start by looking here. Of course, that wouldn't get you the border clipping you describe without some significant extra work… |
Yeah so that is what I proposed, to render the border to texture, minus using the "exact" approach from that old patch. That unnecessarily complicates things for no good reason. I was thinking of the same approach as yours: oversize the texture (or not in the inner border mode), clear with the border colour, then render the actual content that's smaller with offsets so it's centered. The clipping thing isn't difficult; it's more difficult to explain it than to implement. Just a few extra lines of code to the logic that places the texture within the viewport, plus all the windowing logic should use the borderless dimensions. Easy to do in practice if you understand it well what you want to achieve. There is a single thing that only the much more complicated approach can emulate: some games simulated screen shaking by screwing around with the registers that control the border. Frankly, I don't care about this and don't want to complicate the whole thing just to simulate those effects worth a few seconds in total in the 0.0001% of games... |
I use the Hoxs Commodore 64 emulator and it allows you to set the border to just the right and left sides. This effectively makes your widescreen monitor the correct oldschool dimensions and gives you the colored border at the left and right sides. |
With the |
Please see here for timing of the VGA card: https://courses.cs.washington.edu/courses/cse467/03wi/lab/VGA_timing_information.pdf You can also consult the IBM technical references but I can't share those as they are still under copyright. 86Box implements overscan for all the IBM standards so they may be a good resource for understanding of where they derive their overscan amounts. I recommend ripping the band-aid off and doing this the right way. This could mean compatibility issues with 320x200 mode due to line-doubling. The borders are added after the line doubling, which means you will need to process horizontal and vertical borders separately. The horizontal borders should be applied first, with 8 on each side for 640 width modes and 16 on each side for 320 width modes. Note that my understang is that the VGA line doubler doesn't double horizontally (86Box/86Box#3323). The line doubler should then scale the signal vertically, and then the vertical part of the border would then be added. All of this should be considered part of the emulation layer and immutable. A presentation layer will then decide whether to crop or present the borders based on the user's preference. Ideally, this would only be done with shaders, but pratically it's acceptable to have this done in software as a config option. Please note that you will notice the borders change the storage aspect ratio (SAR) of the signal. I'm not exactly sure how to handle this, but it's most likely that given the behavior of CRTs of the time, the 4:3 display aspect ratio (DAR) would apply to the entire visible signal, including the borders. This would mean that in 640x480 mode, the 'square' pixels are actually just a wee bit wide. Overall, it shouldn't affect much, but I think it would be a mistake to try to correct for this by making just the non-overscan area 4:3. Instead, present the entire visible image as 4:3. When cropping is applied, you will get a image that has a DAR of ~1.34. |
Well, I don't agree with any of that. What practical benefits would this extremely hardware-accurate approach bring? Some games/apps use the border to convey information, that's all. It's nice to be able to see that, because we currently don't have that visual feedback. We don't want to make this more complex than that—not even DOSBox-X does that... Implementing a super-accurate-down-to-the-cycle level VGA emulation is not the goal of DOSBox Staging by far. This would add a lot of unnecessary complexity for the code for no good reason, and it would be not in line with our goals. Please see our goals here: https://dosbox-staging.github.io/about/ Screwing around with the ideal 4:3 aspect ratio because of the width of the border... Man, no one cares for that stuff. While technically the border size might affect the actual image size/aspect ratio a little bit, it's a moot point. Tell me one example where the app/game uses some extreme border settings which would substantially alter the perceived aspect ratio, and that was actually the intent of the developer. I would bet good money on it that the number of such programs is exactly zero! To be clear, we are uninterested in adding 3x as much code to the graphics card emulation just that stuff like Area 5150 and similar demos can run (and note these usually require some very specific hardware and refuse to run on anything else because of all the low-level, bang-the-hardware-directly hackery... but they're cool, no doubt... if you can make them run at all 😎). The main goal of the project is to be able to run all DOS era games and a good chunk of application software, that's about it. |
The DOSBox's Team's VGA draw code is compatible with over 10,000 DOS games spanning 25+ years of hardware evolution - more so than any piece of original PC hardware in existence (https://gona.mactar.hu/DOS_TESTS/); so it's pretty hard for me to sit back in an armchair and claim that "DOSBox is doing it wrong". With SDL now providing a hardware-accelerated "flexible" canvas, there is no doubt logic and software-scaling methods that can be eliminated from vga_draw and render.cpp, and might ease the addition of the border ovescan colour. Is that something you're interested in digging into? Touching this code while maintaining performance.. without regressions.. without (further) complexifying the code.. running countless regression tests, is a tall order! My own effort in combining There's a lot of room for improvement, but there's a huge amount of risk for failure and regression. I appreciate the confidence, and yes - like @johnnovak said, if you can refactor it and make it all run: then my hats off to you! Join the effort and dig in 🍝 |
Yeah, please clean up and simplify the graphics card emulation code @anikom15, plus add the border stuff in a clean way, while not breaking any of the 10k+ supported games. If you can do it, we'll merge it in, of course! But screwing around with the 1:1 PAR in modes that are supposed be 1:1 PAR is a bit crazy... I personally won't have any of that. |
Yes, I'll look into it. The trouble is the 320x200 modes, simply because the border in those modes uses effective half-pixels. If that wasn't the case, the borders could be added in one go. Thankfully DOSBox already seems to handle the 320x200 modes in a flexible way. Also, don't rely on 86Box. The border sizes they use aren't always correct. I'd appreciate if anyone could share documentation on the signal timings of the various standards. I have CGA and VGA. I need EGA. I'm sure PCjr and Tandy had their own borders. MDA and Hercules probably have an invisible border as well but that's not as important. Also, I apologize for my tone. I did not mean to suggest a hardware-accurate method (whatever that actually means) was required. I was just trying to offer a way to avoid the potential stumbling block of having to deal with the half-pixel borders in 320x200 mode. |
I'm honestly curious (no irony) where would the "correct" border implementation have any tangible benefits over the proposed simplified approach where you just pick any border width you like, basically? Can you list those programs? In my experience, very few programs use the border colour to convey some information, and for those that do, it does not matter one bit whether the border is 5px, 10px, 20px, or whatever else. Overall, probably 1% of all programs use the border in any meaningful way, making this a rather niche and quite low priority feature anyway. |
Correctness is a tangible benefit to me in itself, personally. But also it's a way to document history. Unfortunately, I have seen many resources, once easily found across the internet, disappear quietly during the past several years. You've probably seen this video of a guy building a video 'card' on a breadboard: https://www.youtube.com/watch?v=l7rce6IQDWs . He wouldn't have been able to build that without a reference on the timing, or at least it would have been a lot more difficult for him to figure it out. |
Note hardware accuracy and "emulation as documenting hardware accurately" is not among our goals, by far. It was never among the goals of the original DOSBox either. Have you ever seen the VGA code? 😎
I appreciate that, and I want that information to be preserved, but this is not the project for that. Some people are writing cycle accurate PC emulators out there, forgot the name. Know what? It can barely emulate anything faster than a 5150 on current hardware with full cycle-accuracy... It's just not practical. I'm all about preservation too, but I think you're barking up the wrong tree here. In DOSBox Staging it's always a balance between accuracy and tangible benefits to the end user, which is 99% of the time people playing old DOS games. Not developing new software, not trying to make the hardware do never-before-seen-things (that would require an 1:1 FPGA re-creation of the hardware anyway), not even running demos that do low-level trickery correctly. Main focus is playing games, that's about it. Getting most apps to work correctly is a bonus we get "for free", kinda. Accurate sound emulation that affects all games and audio being a very important, crucial part of the gaming experience—yes, by all means! Accurate border emulation where the "accurate" border is not an essential part of the experience, and less than 1% of games use the border meaningfully for anything, while complicating the already complicated-beyond-imagination graphics card code (note it's not "accurate" emulation of CGA/EGA/VGA/etc.—it's a mismash of all things that does all gfx card emulation in "one spot"... very messy, and by no means an "accurate representation of hardware". It's "accurate" enough to run 99% of all games correctly, and that's it, it was never any different in DOSBox land). I'm asking again, do you have a list of games where the accurate border emulation makes a big difference for the average user who's not super into accurate border? 😄 Please share the list of games and appications. I've listed some apps at the top where the border conveys info—the "simplified" border emulation I proposed would take care of those. As far as I see it, that approach is sufficient and hits the right balance between complexity, effort, and benefit. Specifically, from our about page, please familiarise yourself with the goals of the project before raising similar tickets and comments (and read the full thing; the non-goals section refers to the "above goals" in the "goals" section): https://dosbox-staging.github.io/about/ |
Having said all that, by all means dig in, and show us how it's done in an easy, accurate, and maintainable way. It has to work correctly in windowed and fullscreen, with shaders, in the texture output mode, handling borders in the screenshots need to be worked out, etc. Looking forward to your design and PR, and if it's great, we'll sure as hell merge it! Otherwise, I'll do as planned. |
Thanks for the feedback. I never suggested a 'cycle-accurate' approach though (cycle accuracy is in itself a myth, but I digress). |
Yes and no. It makes a lot of sense and it's practically mandatory to accurately emulate the timings of the various custom chips in many more advanced home computers, e.g. the Commodore Amiga and the Commodore 64. Without that most games and demos would simply not run. Same for cycle-accurate, flux level floppy emulation; it's mandatory for emulating many copy protection mechanisms. It's more like a sliding scale, and the PC architecture is a lot less advanced and much more decoupled, making a much looser and less accurate approach feasible. But you're right, I always smirk when people say "cycle-accurate" in conjunction with PCem or 86box. They're far from it in all aspects of the emulation, but of course they emulate a whole PC more accurately than the really loose and abstract DOSBox approach with "adaptive, selective" accuracy of specific areas (OPL -- cycle accurate; MT-32 emu -- 95%+ as hardware; VGA -- quite loose but most stuff works; CPU -- emulating a very abstract generic x86 CPU with a very simple MIPS approximation, etc.) Then there are the Macintosh emulators which are really simple as there was barely any hardware in those early machines |
By the way @anikom15 if you care about preserving such info, register an archive.org account and start uploading mirrors/dumps of existing sites that contain useful info about retro computing. I'm doing the same, just I'm limited by available time... |
I would suggest not thinking about the border as something separate - rather think of a display field in totality, and the portion we display being some "aperture" into that field. So for CGA, for example, the entire display field is 912x262 (* ~60Hz = ~14Mhz) We can see as much or as little border as we please by defining an aperture into this field, in this case, I chose a value of 704x224 as the "accurate" setting, just based on aesthetics and a few photographs of scenes on IBM 5153 monitors. It need not be perfect, every monitor was adjusted differently and the picture was not always centered well. The essential bit is not trying to choose a resolution from CRTC registers. The resolution is derived from the dot clock, which is fixed on MDA/CGA, one of two values on EGA/VGA, potentially more on SuperVGA, etc. But the basic method is adaptable to any raster device, although at times your "screen-accurate" aperture may be larger than the field in which case you would pad with the overscan color or black. |
It will have to be considered as something at least partially separate, or else the seamless mouse integration won’t work properly - there will be a strange effect when moving mouse in/out of the screen drawing area. |
Thanks for stopping by @dbalsom. I'm aware of your interests in accurate emulation, but I need to consider practicality here and how this would work together (not against) our existing features. Which includes:
At the end of the day, sure we could implement anything, accurate borders to the max etc... but to what end? Some programs convey important info in the border, and that's it. I'm not interested in doing this 100% accurately, just doing the bare minimum that conveys this info in good old DOSBox tradition 😎 Not interested in those 5 games either that use border tricks to shake the screen, etc. People can live without that, and the code will be much simpler 😄 I definitely do want to implement this as something "tacked-on" at the end of the frame render time. Literally like this in pseudo-code:
We most definitely won't suddenly treat say 640x480 as 645x485 (just making things up and assuming a 5px border). Like I said, I don't want to complicate the code and punish everybody with complexity and weird display resolutions just because 10-20 games use the border for something interesting... It's gonna be literally "tacked-on" at the end of render time, so the mouse code won't be affected either @FeralChild64 then way I'm gonna do this. I just wanna hit the sweet spot here between complexity and usefulness. 😄 We could and probably should do somewhat "accureate" border sizes, so larger for CGA and paper-thing for VGA, etc. Those would be hardcoded and auto-chosen based on the current video mode & graphics standard with EDIT: Read your post again and maybe I misunderstood it and you're saying to "seed" this padding from the dot clock values? I guess that's an option, although as those are fixed per graphics standard anyway, we can just use table of percentage/pixel values anyway, I guess. |
Thanks for the very understandable explanation, @dbalsom; and we couldn't ask for more battle-hardened insights! @johnnovak, my guess is that treating the display as a 2D field that's scanned over at the given MHz rate would mean that line timings would become a lot more accurate, and perhaps some simplicity would fall out of this approach, too. No doubt this change would ripple outward (having to handle or expect a large outbound frame at the rendering, shader, mouse-edges, etc), but my guess this would have to be parameterized (perhaps more so than it currently is). Just thinking about possibilities. |
The current code must do that, otherwise thing would misbehave, I'm pretty sure. It's just only the visible part is rendered. |
There is a surprising elegance to it. Whether you render as an indexed intermediate buffer or directly as RGBA, when you tick a character clock you are incrementing your buffer pointer by as many bytes as the character width (8 for CGA/EGA, 9 for MDA/VGA) or 4x for RGBA. When you reach hsync you reset your pointer position to the next scanline by the field stride, and vsync is just resetting your pointer the start of the buffer again. Nobody needs to be punished by obscure video sizes unless they desire to see them; the 'cropped' aperture values provide the traditional, regular resolutions we are all familiar with, 640x200, 320x200, 640x480, and so on, and if nothing else, they would be safe fallbacks for features that require them. But I am not attempting to tell you how you should design things or what does or does not meet your goals - just suggesting an approach that worked for me and I think has some positive benefits besides emulation of esoterica. |
Thanks for the clarification @dbalsom, I think I slightly misunderstood your previous post. Yes, I think this is probably the best approach from the rendering point of view. The rest of the concerns I listed are unrelated to the pure rendering path, so my bad conflating two related but actually quite separate things 😅 I just have this "big picture" thinking by default: how does X benefit users, how does X fit into our existing set of features, how does X simplify or complicate using the software, etc... Coding comes after that. Probably the result of doing this for 20 years professionally for a living 😆 I original idea (crappy idea) was to copy the rendered image into a larger image to add the buffer. The next idea was to "oversize" the render buffer by the configured border amount, then either pre-fill that with the border colour, or insert some special logic to fill in the border colour at the start and end of lines. Well, basically what you're suggesting is a variation of that approach, so yeah, we're in agreement. |
I'm not entirely familiar with this feature (I'm really curious how you sync up mouse deltas between guest and host...) but seems like maintaining a transformation matrix or such would not be infeasible - you could have a "display aperture" and an "input aperture" and a simple function to convert "display aperture" to "input aperture" coordinates. |
Well, we can't, in the general sense. Games/programs are free to do whatever, so most of the time we have no idea where the mouse pointer is. The seamless mode really only works reliably with the VMware protocol in Windows 3.x that we support as the driver can report absolute positions in that specific protocol. But you need 3rd VMware Win 3.x mouse drivers for that. |
here's a cleaned-up diagram I made to help illustrate the 'field buffer'. This is a standard NTSC diagram to scale, just doubled in height so it doesn't look squished. The idea is that we reset the pointer to the next scanline at the end of the blue bar, and we reset the pointer to the start of the buffer at the end of the purple one, and so on. This moves the left overscan to the left side of the buffer, and the top overscan to the top, respectively. Then we just choose our aperture (sub-rectangle) into the field. These apertures are fixed - as the few games that actually bother to do so adjust the CRTC registers, stuff will move around in the field, but our aperture remains fixed, and the adjustments and screen-shake effects "just work". It's sort of a basic monitor emulation. EDIT: I would be remiss not to mention that I didn't invent this technique, it is pretty standard for Commodore and Amstrad CPC emulation, I just brought it over to PC. |
Overview
On real hardware, the actual drawing area (e.g. 320x200, 640x480, etc.) doesn't fill the whole screen but there's always a border around it (usually black). It is possible to set the colour of this "overscan area" to some other colour than black, and some games and applications use the border colour to convey information to the user. But even when the coloured border doesn't serve any "useful" purpose, it enhances the "retro feel" for people who still remember how real CGA/EGA/VGA output on a CRT looked like.
CGA-like systems
On CGA and CGA-like systems (200-line EGA, Tandy, and PCjr), the overscan colour fills the whole screen, as you can see on the second and third image. There is no way to change the extents of the overscan border in software; the size is hardcoded.
VGA
On VGA, the overscan area is much smaller, usually just a few extra pixels, and most of the black border still remains. The actual size of the border can be controlled via software (there is a dedicated VGA register for it).
In the below video, note that every time something is selected in the menu, the screen goes full red, and then fades to black. When this happens, you can see a small stripe of red outside the visible menu area (the 320x200 actual content area); that's your border background colour on VGA.
https://youtu.be/LM1HYM_qSsw?t=84
Examples
A non-exhaustive list of games that use the overscan area:
Applications that use the overscan area:
Detailed examples
Crystal Caves
FastTracker II
When you toggle Edit Mode by pressing Space, the border changes colour, and there's no other way to tell whether you are in Edit Mode or not.
DOOM, Wolfenstein 3D
When you get hit, not only the screen but also the border flashes red.
Implementation
Currently, DOSBox Staging doesn't support overscan at all. DOSBox-X has limited support, and there was an old experimental proof-of-concept hack that added basic support, but apparently it only ever worked in windowed mode.
Other emulators, such as FUSE, VICE and WinUAE/P-UAE, have been emulating overscan borders right from the start (but to be fair, overscan borders play a much bigger role on the ZX Spectrum, Amiga and C64 than on the PC).
There's some lengthy discussions on the Vogons forum about the exact extents of the overscan area on different graphics adapters and monitors, and ideas about possible implementations (see the references below). I don't think we need to be so super-detailed about it, and I don't think that 100% faithfulness to the original hardware matters either.
The user should simply be able to set the horizontal and vertical overscan borders in pixels or percentages relative to the actual drawing area, and that's it. The borders would always be drawn symmetrically around the actual output, and it would always be "additive", meaning that in windowed mode the window size would be increased by the overscan dimensions, and in fullscreen mode parts of the border would simply be clipped if they wouldn't fit into the screen. If the user wanted to see the full border in fullscreen mode, they would need to restrict the viewport size with
viewport_resolution
accordingly.References
https://www.vogons.org/viewtopic.php?p=328413#p328413
https://www.vogons.org/viewtopic.php?p=421895#p421895
https://www.vogons.org/viewtopic.php?f=32&t=38643&p=348920#p348920
https://www.vogons.org/viewtopic.php?f=41&t=49160&start=60
The text was updated successfully, but these errors were encountered: