mirror of
https://review.haiku-os.org/haiku
synced 2024-11-23 07:18:40 +01:00
docs/develop: a few notes about invalidation, view bitmaps, and overlays
Following some IRC discussions, it seems useful to have this written down somewhere. Change-Id: Ic02686948d989bff2fa671a3831ba5aed1515d25 Reviewed-on: https://review.haiku-os.org/c/haiku/+/6085 Tested-by: Automation <automation@haiku-os.org> Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
This commit is contained in:
parent
53df6323c8
commit
2ab05dc925
@ -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.
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user