Damage as a DIX notion

Keith Packard keithp at keithp.com
Sun Sep 25 16:29:00 UTC 2016


Adam, Eric and I were chatting at XDC about how to make damage
computations more efficient and more useful.

The impetus of this was that glamor on tilers would like to have the
bounds of every operation to reduce the number of tiles processed for
small operations. Damage already computes the bounds of every operation,
but that bounds is not available to glamor. Re-computing the bounds
would be wasteful, so instead we want to capture the computation done
(potentially) by damage instead of redoing it.

I've taken a couple of stabs at a design, and I figured I'd share my
current ideas to get some feedback.

First off, I think I need a set of bounds computing functions, one per
rendering operation. I've started writing these to compute a simple
bounding box for an entire operation. This may be larger than what
Damage currently computes, but I don't think a closer bounds is
interesting for most operations.

Next, I think we just want to pass any computed bounds along with the
rendering operation. This means tacking on another argument to all of
them. A NULL value means that no bounds have been computed yet.

Finally, each element in the stack which needs the operation bounds will
have a local BoxRec to hold a bounds, and then call the
operation-specific bounds function, which will either use the existing
bounds (if non-NULL), or fill in the local BoxRec and return that.

Here's a sample of these new functions:

        BoxPtr
        bounds_poly_point(DrawablePtr drawable,
                          GCPtr gc,
                          int npoint,
                          const xPoint *points,
                          BoxPtr bounds,
                          BoxPtr local_bounds)
        {
            int i;

            /* Are the operation bounds already computed? */
            if (bounds != NULL)
                return bounds;

            /* Compute bounds of this operation */
            bounds = local_bounds;
            if (npoint == 0) {
                *bounds = bounds_empty();
                return bounds;
            }

            open_rect_to_box(bounds, points[0].x, points[0].y, 1, 1);
            for (i = 1; i < npoint; i++)
                open_rect_union(bounds, bounds, points[i].x, points[i].y, 1, 1);
            bounds_trim_gc(drawable, gc, bounds);
            return bounds;
        }

Here's how the Damage layer uses this:

        static void
        damagePolyPoint(DrawablePtr pDrawable,
                        GCPtr pGC, int npt, const xPoint * ppt,
                        BoxPtr bounds)
        {
            BoxRec local_bounds;
            DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable);

            if (checkGCDamage(pDamage, pGC)) {
                bounds = bounds_poly_point(pDrawable, pGC, npt, ppt, bounds, &local_bounds);
                if (!bounds_is_empty(bounds))
                    damageDamageRelBox(pDrawable, bounds, pGC->subWindowMode);
            }
            (*pGC->ops->PolyPoint) (pDrawable, pGC, npt, ppt, bounds);
            damageRegionProcessPending(pDamage);
            DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable);
        }

We can obviously change the internals of Damage so that we just pass the
damage box to damageRegionProcessPending; that will greatly simplify the
internals of that code.

Now, down in glamor, we can do the same thing to compute the bounds as
needed. Here's how a glamor fallback works:

        static void
        glamor_poly_fill_rect_bail(DrawablePtr drawable,
                                   GCPtr gc, int nrect, const xRectangle *prect,
                                   BoxPtr bounds)
        {
            BoxRec local_bounds;

            glamor_fallback("to %p (%c)\n", drawable,
                            glamor_get_drawable_location(drawable));
            bounds = bounds_poly_fill_rect(drawable, gc, nrect, prect, bounds, &local_bounds);
            if (glamor_prepare_access_box(drawable, GLAMOR_ACCESS_RW, bounds) &&
                glamor_prepare_access_gc(gc))
            {
                fbPolyFillRect(drawable, gc, nrect, prect, bounds);
            }
            glamor_finish_access_gc(gc);
            glamor_finish_access(drawable);
        }

If Damage has already computed the bounds of the operation, then glamor
can re-use that value. Otherwise, it will compute the bounds itself to
reduce the amount of data shuffled.

I've written just a smattering of the code as I'm assuming we'll improve
this design and probably end up replacing all of the code. I had
initially thought that we'd want to take advantage of the patches I've
sent around which make the rendering data immutable, but that isn't
necessary for this design.

The current design has one serious problem, and I don't have a solution
in mind yet. When you draw something that is implemented in terms of
other drawing operations (like mi lines/points/arcs etc), and if Damage
isn't being tracked on the drawable, then the bounds are never computed
for the higher-level operation, and instead you end up computing bounds
for all of the low level objects instead (e.g. spans).

What we might want is for the lower level operation to somehow get ahold
of the highest level operation and use that to compute the bounds, but
that seems like a lot of bookkeeping for an unusual case.

I'm tempted to just ignore the problem for now; the spans will get
bounds compute as necessary and that will work fine. However, if someone
has a great idea, I'd love to hear it.

-- 
-keith
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <https://lists.x.org/archives/xorg-devel/attachments/20160925/8cd9e6cf/attachment-0001.sig>


More information about the xorg-devel mailing list