Re: OS Graphics
Posted: Tue Aug 06, 2013 7:43 pm
Hi,
For graphics, an application builds a "list of commands" in the message buffer and doesn't have to worry about memory management for that at all. The only real problem is that the size of a message is limited to 2 MiB (e.g. if you assume that each command costs an average of 40 bytes you end up with about 50000 commands in a list). For a 3D game (e.g. with a huge number of polygons on screen) this might sound like a problem; but it's not. For example, you might have an army of 1000 people, but that might be one list describing an arm, one list describing a leg, one list describing a head, etc; with a separate lists describing each person (where to put arms, legs, etc), then a master list saying where each person is. For applications it'd be the same (e.g. one list for a widget, one list for a toolbar, one list for a status bar, etc; with a master list saying where each of the smaller pieces are). This also means that applications/games only need to send lists of commands that changed - you don't send all lists every time. For example (an army of 1000 people) one soldier might move his arm, so you don't send lists to describe an arm or leg, or the landscape, buildings, tanks, trucks, etc because none of them changed.
Basically; as far as the applications, GUI, etc are concerned most of the memory management happens automatically. For the video drivers it's a different story though (they'd need something more advanced than just "malloc()" because they'd be managing "cached textures", etc).
For how long it'd take to draw a frame, it depends too much on too many things to say. There's lots of opportunities for optimisation within the video driver (e.g. not drawing obscured things, using caches to avoid redrawing pieces that didn't change, etc) so you'd rarely need to redraw everything from scratch. Note: I imagine it as a recursive thing, where you start with the list of commands for the entire screen and "draw" it to determine which child lists are needed, then draw the children to find out which of their children are needed, etc; where you might have a suitable cached texture that prevents the need to draw a list of commands again (or it's children, or it's children's children).
On the other side of this, the video driver is able to draw things again if it wants to. For example, the video driver might reduce rendering detail in an attempt to get a frame done in 1/60th of a second, and then (if nothing changes) do it again with higher detail. For normal applications and GUI this can mean faster response times (e.g. get it displayed fast, then get it displayed with higher detail before the user has had a chance to realise the first frame was low detail). For 3D games it could mean everything is moving around and you didn't need higher detail anyway, but then the user pauses the game.
For example, one of my monitors is smaller than the other (less wide and slightly less tall), and the smaller monitor has a "16:10" aspect ratio and the larger monitor has a "16:9" aspect ratio. If both monitors used the same resolution it'd look like crap - a window spanning both monitors would be large on one monitor and smaller on the other and half of it would be stretched a little in one direction. To cope with that; I've got the larger monitor set to 1920*1200 and the smaller monitor set to 1600*1200, just so that the OS doesn't screw up the sizes and also screw up the aspect ratios. This only works sort of - it's not perfect and windows on the smaller monitor are slightly larger than they should be. Worse; the smaller monitor is not using it's native/preferred resolution, which means that the monitor itself has to scale the image to suit its LCD screen (which is guaranteed to cause a "worse than perfect" image).
Basically most OSs do support multiple monitors; but unless both monitors are the same size and using the same resolution, it does not work properly. For my OS I'd be able to have both monitors running at their native resolution without any problem at all.
Note: The only thing I was trying to say here (and am continually trying to say) is that nobody needs to care how any renderer works (unless they're writing that renderer).
Of course not needing to care how any renderer works includes not needing to care if your "lists of commands" are being sent to a video driver and used for a 2D monitor, or being sent to a video driver and used for some kind of a "3D stereoscopic" display, or being sent to a 2D printer, or being sent to a 3D printer, or being sent to a file, or being sent across the internet to a user on the other side of the world, or...
Cheers,
Brendan
Yes; and this includes all sorts of things. E.g. if the user changes video mode the GUI and all applications won't need to know; if the users (or GUI) zooms in or out on a window (or rotates a window) the application won't need to know, etc. This means less communication between processes (less task switches, etc). More importantly; for a distributed system like mine it also means faster response times (as you can redraw without sending messages to other computers and having network latency in both directions).MessiahAndrw wrote:1) You can do vector graphics!
You don't need to issue a redraw event when you to resize a window! Some applications may still want to do this of course (you resize a Firefox window, Firefox will want to use want to use that extra space to show more of the webpage, rather than make everything scale larger.)
Yes - it can be 100% "tear free", without having something that causes delays (e.g. a lock shared by application and GUI, where GUI has to wait until application releases the lock) and without having extra pixel buffers.MessiahAndrw wrote:2) Asynchronous rendering
A really simple example - I am writing an Emacs like text edit that is using Lua (was using Google's v8 Javascript but I ran into overhead issues switching between sandboxed instances) - these high level languages are very slow at bit twiddling, so that's something I have to avoid all together. Instead I use Cairo. When it comes time to redraw the window, I have a loop that goes over each frame (displaed document) and says (pseudocode):
For my messaging system, the application builds messages (which can be up to 2 MiB) in a special "message buffer" area; and the kernel's virtual memory manager knows about the message buffer area and does "allocation on demand" to automatically allocates pages if/when needed. When the message is sent the pages are moved (not copied) leaving the message buffer area empty (as if the pages were freed).MessiahAndrw wrote:2. Dynamic allocation/memory usage
You'll have to consider that the buffers may rapidly change size between frames. If you add a new GUI component, that may be an extra 10 commands. It's unlikely that an application will know how many commands it is about to draw, until it draws them, so likely you'll have to dynamically expand the buffer as you write to it.
For graphics, an application builds a "list of commands" in the message buffer and doesn't have to worry about memory management for that at all. The only real problem is that the size of a message is limited to 2 MiB (e.g. if you assume that each command costs an average of 40 bytes you end up with about 50000 commands in a list). For a 3D game (e.g. with a huge number of polygons on screen) this might sound like a problem; but it's not. For example, you might have an army of 1000 people, but that might be one list describing an arm, one list describing a leg, one list describing a head, etc; with a separate lists describing each person (where to put arms, legs, etc), then a master list saying where each person is. For applications it'd be the same (e.g. one list for a widget, one list for a toolbar, one list for a status bar, etc; with a master list saying where each of the smaller pieces are). This also means that applications/games only need to send lists of commands that changed - you don't send all lists every time. For example (an army of 1000 people) one soldier might move his arm, so you don't send lists to describe an arm or leg, or the landscape, buildings, tanks, trucks, etc because none of them changed.
Basically; as far as the applications, GUI, etc are concerned most of the memory management happens automatically. For the video drivers it's a different story though (they'd need something more advanced than just "malloc()" because they'd be managing "cached textures", etc).
For a native video driver I'd use page flipping (2 buffers, one being displayed and the other being drawn into, where you switch from one to the other); and for software rendering (e.g. "LFB only video") you'd need a buffer in RAM (and blit that buffer to display memory). Either case doesn't seem like a problem.MessiahAndrw wrote:3. Performance
Your main concern is to prevent the copying of pixels. Above, I discussed how we would need to do triple buffering (at the expense of some memory) to avoid very locking while copying between your drawing and screen buffers.
You can even triple buffer pixel buffers to avoid copying them, until the final moment when you want to compose everything on the screen into one image to send to your video card.
At some point, you will have to execute your command list. If your whole OS graphics stack is abstracted away from the pixel, then this will be done at the final stage in your graphics driver. Will you be able to execute this command buffer fast enough during the v-sync period, to avoid the 'flickering' I mentioned early about having a semi-drawn image displayed on the screen?
For how long it'd take to draw a frame, it depends too much on too many things to say. There's lots of opportunities for optimisation within the video driver (e.g. not drawing obscured things, using caches to avoid redrawing pieces that didn't change, etc) so you'd rarely need to redraw everything from scratch. Note: I imagine it as a recursive thing, where you start with the list of commands for the entire screen and "draw" it to determine which child lists are needed, then draw the children to find out which of their children are needed, etc; where you might have a suitable cached texture that prevents the need to draw a list of commands again (or it's children, or it's children's children).
On the other side of this, the video driver is able to draw things again if it wants to. For example, the video driver might reduce rendering detail in an attempt to get a frame done in 1/60th of a second, and then (if nothing changes) do it again with higher detail. For normal applications and GUI this can mean faster response times (e.g. get it displayed fast, then get it displayed with higher detail before the user has had a chance to realise the first frame was low detail). For 3D games it could mean everything is moving around and you didn't need higher detail anyway, but then the user pauses the game.
I don't think it's unrelated at all. Most OSs allow you to have windows span more than one monitor; but there's severe restrictions and work-arounds for those restrictions.MessiahAndrw wrote:4. Multi-monitor rendering
I think this is unrelated to command lists vs. pixels. Every multi-monitor machine I've used has allowed me to have windows span more than one monitor.
For example, one of my monitors is smaller than the other (less wide and slightly less tall), and the smaller monitor has a "16:10" aspect ratio and the larger monitor has a "16:9" aspect ratio. If both monitors used the same resolution it'd look like crap - a window spanning both monitors would be large on one monitor and smaller on the other and half of it would be stretched a little in one direction. To cope with that; I've got the larger monitor set to 1920*1200 and the smaller monitor set to 1600*1200, just so that the OS doesn't screw up the sizes and also screw up the aspect ratios. This only works sort of - it's not perfect and windows on the smaller monitor are slightly larger than they should be. Worse; the smaller monitor is not using it's native/preferred resolution, which means that the monitor itself has to scale the image to suit its LCD screen (which is guaranteed to cause a "worse than perfect" image).
Basically most OSs do support multiple monitors; but unless both monitors are the same size and using the same resolution, it does not work properly. For my OS I'd be able to have both monitors running at their native resolution without any problem at all.
If you've got an application that describes a scene and a renderer that draws that scene; then the application has no reason to care how the renderer works internally. My OS will work like this, which means that the only person that needs to care how any renderer actually works is the person writing the code for that specific renderer. Everyone else can just assume that all renderers "attempt to loosely approximate the results of applying physical model of light to the scene" without giving a rat's arse how the renderer actually does this (or whether the renderer actually does do photon tracing, or something radically different like rasterisation, or anything else).MessiahAndrw wrote:It is true, the physics of light do not change. However, computers are yet to reach the stage when we are able to simulate, even just a room, at a fine grain atomic level in real time. Real-time ray tracing is barely reaching that level, real-time photon tracing is still way off. Rendering graphics is all about using approximations that give an effect that is "good enough" while maintaining acceptable performance.Brendan wrote:The physics of light do not change. The only thing that does change is the "scene"; and this is the only thing an application needs to describe.
Note: The only thing I was trying to say here (and am continually trying to say) is that nobody needs to care how any renderer works (unless they're writing that renderer).
Of course not needing to care how any renderer works includes not needing to care if your "lists of commands" are being sent to a video driver and used for a 2D monitor, or being sent to a video driver and used for some kind of a "3D stereoscopic" display, or being sent to a 2D printer, or being sent to a 3D printer, or being sent to a file, or being sent across the internet to a user on the other side of the world, or...
Sure; and I'll probably (eventually) want to allow video driver's to have built-in shaders for all these things. There's no reason for each different application/game to provide them.MessiahAndrw wrote:What are some effects that are hard to do without shaders? Rim lighting, cell shading, water (particles as metaballs that are calculated in screen space, foam and mist), soft particles, ambient occlusion, motion blur - and custom lighting pipelines like deferred lighting and pre-pass lighting (which would require a render pass per light in traditional rendering) that is best suited to a particular application. Vertex shaders let you calculate do animation on the GPU (so you're not always having to upload a new vertices with new positions each frame) - flapping flags, water waves, skeletal animation. Tessellation shaders allow you to insert vertices at runtime, purely on the GPU, based on dynamic parameters such as textures and the camera position, preventing you from having to a) continuously stream new vertices to the GPU, and b) having to upload large geometry to the GPU, when you can you just upload a flat plane to the GPU and let the tessellation shader do the rest.
Let's test this. Get 5 computers connected via. gigabit ethernet. Only 2 of these computers need to have video cards and the rest shouldn't have any to save costs. Plug one monitor into one computer and another monitor into another computer. Then run a GUI on the third computer (such that the GUI is using both monitors). Start a 3D game on the fourth computer and another 3D game on the fifth computer (so those games are running in windows on the GUI). Arrange the game's windows so they're split across both monitors. Let me know what sort of performance you get pushing massive quantities of pixels around the network; for both Windows and Linux.MessiahAndrw wrote:However, a general purpose operating system is likely to want to support all kinds of dynamic content, including media, web pages, video games - in which case, after thinking deeply into it, I still think you would gain better performance using traditional pixel-based buffers implementing a fast lockless triple buffering system that prevents any copying until the final image is composed on to the screen.
Cheers,
Brendan