app_server

Using the remote app server

Article contributed by PulkoMandy on Thu, 2014-06-12 09:46

What it is

One little known feature in Haiku is the ability to run apps on a remote system, similar to rdesktop for windows or the more common VNC. Unlike VNC (which is also available), the remote app server forwards app_server calls through the network and let the drawing happen on the client side (where the screen is). This is actually quite similar to X forwarding on unix systems.

How to use it

You need two machines running Haiku, one is the server (where the apps run), and the other is the client (where the display is).
The server needs to be configured to allow ssh access (add the sshd user, and set a password for the default user). The client needs the RemoteDesktop app, which currently needs to be compiled from the Haiku sources with "jam RemoteDesktop".

With the server powered on and online, go to the client and run:

RemoteDesktop user@host

Enter your password when requested. The app will open a fullscreen window on the current workspace and start a remote terminal inside it. From there you can start apps and do whatever you want on the remote end!

The quirks

There are several things you need to be aware when using this.

First, the redirection is done on a per-application basis, so it is not possible to use the same app both as a remote and local one. For example, if you try to start DeskBar from the remote terminal, it will instead open DeskBar preferences on the server display. You need to close the existing Deskbar (hey Deskbar quit) and start it again on the remote end. The same will happen if Terminal is already open on the server when the client connects. In that case, the app will leave you with a blank window where you can do nothing.

The RemoteDesktop is a fullscreen window, there is no "rootless" mode. You can, however, have local windows shown above it.

With some more testing, and a better error handling and more friendly interface, this could be made part of the default haiku install. Help us testing it and squashing the bugs!

Brainstorming notes: Implementing alpha-masks in Haiku

Article contributed by PulkoMandy on Fri, 2014-01-24 13:57

This article attempts to sum up a discussion I had with stippi over IRC about how to implement this.
Most of the ideas and design are his work, not mine. I'm just turning this into a more readable form and archiving it on the website.

Requirements: what are alpha masks, and why do we want them?

I've covered this in an existing blog post.

Short version: WebKit renders "blocks" of an HTML page (span, divs, and the like). It does this by entering one block, setting a clip region to it's limits, drawing everything inside (possibly entering more blocks and constraining the clipping further), then moves on to the next block.

When you use some (not-so-)advanced CSS features, such as border-radius, you can end up with a block whose clipping isn't a simple rectangle, but instead a more complex shape. We currently don't implement this, leading to some drawing artifacts: things are either not being drawn, or drawn at places where they shouldn't be.

API design

It turns out the BeAPI already plans for this feature. BView has a ClipToPicture (and ClipToInversePicture) call, allowing to clip the drawing of a view to any custom shapes. There are a few problems with this, however:
- There is no support for antialiasing
- Our implementation is extremely slow
- On BeOS, the clipping is done in view coordinates, ignoring the scale and origin of drawing

The first two points are implementation problems: we implement this method using ConstrainClippingRegion, which clips drawing using a region. A region can't have half-pixels, and, a complex region that covers exactly the pixels covered by a picture is expansive to build. and, WebKit keeps changing the clipping all the time as it moves between rendering blocks.

The third item comes from a different need in BeOS: there, the method was used to have non-rectangle BViews. You would clip a child view to a picture of itself, so it doesn't draw its background, then you would clip the parent to the inverse picture, so it draws the remaining pixels.

There doesn't seem to be much apps using ClipToPicture this way (or at all: not a single call to it exists in the Haiku code base, except for test applications that are testing it). So, we decided to trade compatibility for sanity, and go with a clipping that works in object space instead of view space. This means the clipping can be scaled and translated with the rest of the drawing. The old behavior can still be achieved, by setting the clipping, then pushing the view state. While this way of working is not usual in the BeAPI, it will avoid a lot of nonsense when we get to implementing view transformations. If it proves to be a problem for compatibility (Gobe Productive is known to use this kind of clipping), we can add a compatibility test and have it work another way for old apps.

Implementation choices

To support the transformable mask we want, we have to keep the picture object around. While drawing, and as the state of the view changes, we need to generate a bitmap rendering of it, and use that as a clipping mask in app_server's Painter. Whenever possible, the bitmap must be cached, so most of the usual cases, where the clipping isn't changed very often, can be handled reasonably fast.

The masking code must be added and removed dynamically in the agg rendering pipeline. We don't want views that don't use ClipToPicture to be slowed down, and the alpha masking is an expensive operation that implies a lot of hit-testing and blending.

The masking must not be done per-pixel, this would be too slow. Instead, agg allows us to do the masking at the scanline renderer level. This is faster, because it actually clips out the drawing operations that are completely masked, and keeps the ones that are completely opaque reasonably fast. Other operations may be split in an opaque, a transparent, and a transition area between the two.

Architecture

We introduce an AlphaMask class that keeps the masking state. This includes at least:
- The masking picture, as a ServerPicture object, as we got it from the client,
- Part of the drawing state: pen size, drawing modes, and a few others. This should actually be part of the clipping picture, in order for it to be drawn in the same way each time.
- A lazily initialized cached rendering of the picture as a bitmap. This can be used as long as the drawing state stays the same. Changes to the drawing state don't trigger an immediate redraw of this, however, they could mark it as 'dirty'. When the alpha mask is about to actually be used for drawing, we make sure we have an up to date bitmap, and give it to the Painter so it can make use of it.

The actual masking happens in our Painter class. The two main methods that need rework are _StrokePath and _FillPath. Other methods need to be adjusted to call those (skipping eventual optimized versions) when a clipping picture is set. And these two methods must get an extra if-clause to handle the alpha masked case.

There also need to be dedicated code for bitmap and text drawing. These aren't drawn using path code, but a different codepath ;). We have to find a way to clip them too.

ClipToInversePicture problems

The agg masks implementation lack some features we need. To avoid wasting memory, we want the alpha mask to be just big enough to hold the BPicture (this could be much smaller than the complete view side). but this means the mask may not be aligned with the view, and instead would start at an offset. Agg default clipping implementations don't seem to allow this in an obvious way. It may be possible to trick them by using a render_buffer that itself offsets the picture.

We have a similar problem for the inverse picture case. Here, we may still have a very small picture, but we must also include anything that's outside of the bitmap. AGG alpha masks consider anything outside the bitmap to be clipped out.

We have several ways to avoid that:
- Make the bitmap always the same size as the view. This means we don't have to care about out of bounds access, but we don't get to use the fast code path when drawing pixels outside of the picture area
- using a custom alpha mask subclass that can include everything outside the bitmap. This saves memory as the bitmap can be small again, but again, we may not get to use the fast codepath
- have an hybrid region/pixel system, where we first clip using a BRegion, then fill the holes using the slower bitmap clipping. While this sounds like a great idea, the semantics are a bit unclear as the BRegion is only binary. We'd need a 3-state BRegion where each rect could be either included, excluded or "I don't know, have a look at the bitmap"). This would get us the fast region-clipping in most cases, except in the area where pixel-clipping is in effect (or we could even reduce that to just the edges of that area, where antialiasing occurs). This is probably the best solution, but the most complicated to implement.

State stacking

An important feature we have to retain is the ability to push and pop view states, and have the clipping follow this. While this was relatively easy to implement for region clipping, it can get more tricky for alpha masking.

We have to intersect the BPictures from all stacked states to generate the actual clipping bitmap.
Even when the current state changes, we may have to recompute bitmaps for the lower levels, for example because the view was resized or scrolled, and we don't have a bitmap for the newly exposed areas.

In this case, we must do the following:
- Start with the lower layer in the stack
- Compute the mask for it, taking the current view size and scrolling into account
- Use the generated bitmap to mask the drawing of the above layer
- ... and so on until we get to the top of the stack.

Note this will only happen in the cases where the view is scrolled or resized. This doesn't happen during regular drawing operations, only between them, and we expect the state stack to be small in those cases. So, the overhead of rebuilding all the bitmaps isn't that much of a problem. As changing the view origin and scale while drawing doesn't affect pushed states in any way, they don't trigger any such rebuild.

How to transform the app_server code to use compositing

Article contributed by stippi on Wed, 2011-06-15 11:14
The topic of implementing compositing in the app_server comes up once in a while. I have outlined my thoughts on the subject more than once, but these are burried in mailing list archives. Since I have just written another overview of how this could be approached, I thought I might better put this up as an article here, so I can point people to it in the future. I am going to give an overview only. It is intended to help anyone along when reading the app_server code and piecing things together. These are direction that I think are guaranteed to work OK, and with the minimal amount of changes, but anyone taking up this task needs to figure out the actual implementation himself, of course. Here it goes...
Syndicate content