diff --git a/docs/develop/servers/app_server/graphics.rst b/docs/develop/servers/app_server/graphics.rst index 2de134efcd..30dddcd8ed 100644 --- a/docs/develop/servers/app_server/graphics.rst +++ b/docs/develop/servers/app_server/graphics.rst @@ -1,6 +1,28 @@ Graphics ========= +Design overview +--------------- + +The app_server drawing system was designed in BeOS with the goal to provide low latency response +(it should look fast), making use of the quite powerful CPU, but somewhat limited RAM available +at the time. + +As a result of these constraints, in BeOS the app_server operated with a single buffer framebuffer +(there was not enough RAM and especially not enough video RAM to enable double buffer). It is also +designed to use 2D acceleration whenever possible, to free up the CPU for other, more interesting +tasks. This is achived by the use of "accelerants", add-ons loaded into app-server that communicate +with the kernel part of graphics drivers. Usually the kernel part will be as minimal as possible, +providing low-level access to the video card (command ring buffers, memory mapping of registers, +DMA setup, that kind of things), and the accelerant will be doing the higher level work on top of +it. Note, however, that on modern hardware, the graphics card acceleration is often not that fast +for 2D work, compared to the power offered by multi-GigaHerz CPUs. So, Haiku does not currently use +most of these acceleration features, doing its drawing using the CPU instead. + +The single buffer approach creates a problem: applications that are too slow to redraw things can +result in "glitches" on screen. These are of mainly two types: flickering and stamping. The +app_server in Haiku takes some care to avoid these. + Desktop Initialization ----------------------- @@ -133,6 +155,40 @@ action. Screen Updates -------------- +Managing invalidation +..................... + +The drawing is architectured around a single framebuffer, where all windows can draw. +In general, redrawing should be avoided when not necessary, and if possible, multiple drawing +requests should be combined together to avoid redrawing the same area over and over. + +To achieve this, a protocol to decide which parts of the screen need to be redrawn is implemented. + +When something needs to change, that region is marked as "invalidated" and the app_server will +ask the corresponding view to redraw itself. Invalidation can happen in two ways: + +- Window management events (a window was resized or hidden, for example) +- The application asked to redraw something by calling Invalidate() + +These two are handled slightly differently. When the event comes from window management, one of +the views involved will have parts of it newly exposed (previously they were hidden by another +window that is now hidden, or they were outside the window bounds, for example). In this case, +app_server will immediately fill the newly exposed area with the view color. This avoids one of +the two drawing problems when applications are too slow to redraw: stamping. For example, if one +windows is not redrawing fast enough, and another is moved above it, that movement will quickly +hide and re-expose parts of the bottom window. If the window does not redraw fast enough, and +nothing is done, we would be left with parts of the top window being partially drawn where they +shouldn't be anymore. + +In the case of invalidation coming from the view itself, however, things are a bit different. We +can assume that the view had already drawn something at that place. If we cleared the area to the +view color, and the view takes a little time to redraw, this would result in flickering: the view +would be briefly visible with only its view color, and then redrawn with its content again. So, +in the case of invalidation, the app_server does nothing, and waits for the view to redraw itself. + +Getting things drawn on screen +.............................. + Screen updates are done entirely through the BView class or some subclass thereof, hereafter referred to as a view. A view's drawing commands will cause its window to store draw command messages in a @@ -147,6 +203,56 @@ such as StrokeRect, will involve the ServerWindow object calling the appropriate command in the graphics module for the Layer corresponding to the view which sent the command. +The commands are grouped together in a drawing session, that corresponds to a call to the +BView::Draw() method. In Haiku, the app_server uses double buffering, and all the drawing from +one session will be done on the backbuffer, and moved to the front buffer only when the session is +complete. The normal workflow is to trigger this by a request to draw something (either an +"expose" event because a part of the window has become visible, or a call to the Invalidate function +from the application side). However, it is also possible for views to send "unsollicited" drawing +commands outside of an update session. While this will work, the lack of a session means each +command will be handled separately, and immediately copied to the front buffer. As a result, there +will be more fickering and the drawing will be a lot slower. + +When interpreting the drawing commands, app_server will prevent any drawing from happening outside +the area designated for a given view, including parts of it that could be hidden by other windows. +There is an exception to this, however: when using BDirectWindow, it is possible to access the +whole frame buffer. In this case, app_server provides the application with a BRegion it should +redraw, and it is up to the application to not draw ouside those bounds. + +Offscreen views +............... + +When a view does very complex drawing, that will take more than a frame to complete, the single +framebuffer design is not desirable, and will result in a lot of flickering as partially drawn +states of the view are shown on screen. To avoid this, the app_server provides the option for a +view to draw off-screen, into a BBitmap. When the bitmap is complete, it can then be put on-screen +using another view. + +This can be done in two ways: either using DrawBitmap() or SetViewBitmap(). The latter is better, +since it simply lets app_server know that the view should show that bitmap, and then there is no +need to do anything to handle expose and invalidate events, the app_server can automatically draw +the bitmap instead of using the view color to fill the newly exposed or invalidated area. + +Overlays +........ + +When view bitmaps are not enough, it is possible to go one step further: have the hardware insert +the picture inside a view, instead of app_server having to copy it in the framebuffer. This is +achieved using overlays. The API is similar to SetViewBitmap, but the bitmap is allocated directly +in video memory and managed by the video card. Unfortunately, not all video drivers currently +support this feature. + +It is possible to mix overlays with normal drawing. The overlay is normally made visible only when +the framebuffer is a certain specific color(usually pure green or pure magenta, the specific +color is determined by the graphics driver and multiple colors may be used for multiple overlays +from different views, if the hardware can do that). The application can then simply let the view be +filled with that 'color key' (setting it as the view color), or it can draw other things that will +be displayed over the 'overlay' picture. + +Depending on the graphics hardware, overlays can also be resized in hardware, and use a different +colorspace from other parts of the framebuffer (for example, a video overlay can be in YUV format +while the framebuffer is in RGB or even in a 256 color palette mode). + Cursor Management ----------------- @@ -170,3 +276,4 @@ machine for the remote_app_server, or drawing for a specific window can be grant to the framebuffer on a specific display and video card, while other applications go through the normal process of drawing only to their currently exposed region only. +