Gecko:Layers: Difference between revisions

1,294 bytes added ,  29 October 2009
Line 91: Line 91:
Implicit layers can also change size, need to be scrolled, etc.
Implicit layers can also change size, need to be scrolled, etc.


=== Old proposal ===
=== Proposal ===


I may need to revise this quite a bit based on the previous section.
==== LayerManager ====
 
Every layer belongs to a LayerManager. The idea is that a window will provide an associated LayerManager. (Documents being rendered by their own process will probably have their own LayerManagers.) Every layer in a layer tree must have the same LayerManager.
 
Updates to the layer tree are performed within a transaction. Nested transactions are not needed or allowed. Only layer tree states between transactions will be rendered. Unless otherwise noted, all layer-related APIs
may only be used within a transaction on the appropriate LayerManager, and only on the main thread.
 
class LayerManager {
  void beginTransaction();
  void setRoot(Layer*);
  void endTransaction();
};
 
LayerManager::SetRoot sets a layer to be the root layer. This is how you get a layer to be displayed.
 
==== Layer ====
 
Layer is the superclass of all layers. A Layer could be anything that can be rendered into a destination surface. It has methods to set various properties that affect the rendering of a layer into its parent: opacity, transform, filter, etc... (For simplicity I'm only showing 'opacity' here.)


// Reference counted, safe-for-cross-thread-use layer class.
// Conceptually it's just something that knows how to composite itself
// onto some parent surface/layer.
// Layers are immutable. They might have time-varying rendering (animation),
// but you can't modify one once it's created. This makes them easy to use
// safely across threads.
  class Layer {
  class Layer {
  LayerManager getManager();
  void setOpacity(TimeStamp, float);
  };
  };


class FunctionOfTime<T> {
Animated properties are supported. To animate, call a setter method one or more times, passing in different timestamped values. When we render, we use the last supplied property value that is before the current time. When calling a setter method with TimeStamp T, all values for times >= T are discarded. To set a constant value, just pass a null TimeStamp, which is interpreted as being at the beginning of time.
  // We assume that we can access the frame rate to figure out how many
 
   // samples we should provide
Layers should be referenced counted. The LayerManager holds a reference to its root layer and parent layers hold references to their children.
   static FunctionOfTime createSeries(TimeStamp start, TimeDuration duration,
 
                                      int numSamples, T* values);
==== RenderedLayer ====
  };
 
A RenderedLayer is the basic leaf layer that you can render into using cairo/Thebes.
 
class RenderedLayer : public Layer {
   RenderedLayer(LayerManager, ContainerLayer parent);
 
   gfxContext* beginDraw(const nsIntRegion& aVisibleRegion,
                        const nsIntRegion& aChangedRegion,
                        nsIntRegion* aRegionToDraw);
  void endDraw();
 
  void copy(RenderedLayer, const nsIntRegion& aRegion,
            nsIntPoint aDelta);
  }
 
RenderedLayers are conceptually infinite in extent. Each RenderedLayer has an internal "valid region" which is finite. (An implementation would create a surface large enough to hold the entire valid region.) The initial valid region is empty. The implementation is allowed to discard all or part of the buffered contents of a RenderedLayer between transactions. Drawing into the RenderedLayer adds to the valid region, and discarding parts of the buffer removes from the valid region.
 
When calling beginDraw, the caller specifies in aVisibleRegion a region that needs to be valid when drawing is done. (This is the area that will be visible to the user.) The caller can also specify aChangedRegion to indicate that content in that region has changed and will need to be repainted. The implementation returns aRegionToDraw to indicate the area that must be repainted. Typically this will be aNeedRegion minus (the currently valid region minus aChangedRegion). aRegionToDraw is added to the valid region.
 
The content in a RenderedLayer can change size. If the size decreases, aChangedRegion will include the area of content that has gone away, and aVisibleRegion will exclude that area. The implementation may trim its buffers appropriately. If the size increases the implementation will need to increase the buffer.


// Generic superclass for helper object that creates a layer. This can only
It is possible for aRegionToDraw to return empty, e.g. when nothing changed and the entire visible area is still buffered. The caller should optimize by skipping painting in this case.
// be used on one thread.
class LayerBuilder {
  // Indicate that the given layer is related to this one, e.g., the new layer
  // corresponds to the same element as the given layer.
  // We can use this to predict that the new layer will be used in the
  // same way as the given layer, for example, the eventual rendering
  // destination(s) of the new layer can be predicted to be whatever the old
  // layer was rendered to.
  void setAffinity(Layer);
  // Set rendering properties
  void setOpacity(float);
  // Set the transform used to render this layer onto the destination surface
  void setTransform(matrix);
  void setColorSpaceConversion(...);
  void setProgram(...);
  // Set animated rendering properties. The layer is still immutable from
  // the API point of view, but its properties will change over time.
  // Specifying a function over time here lets a compositing thread change
  // the properties without blocking on the main thread.
  void setAnimatedOpacity(FunctionOfTime<float>);
  void setAnimatedTransform(FunctionOfTime<matrix>);
  // Finish building and return the Layer. This can only be called once,
  // nothing else can be done with this LayerBuilder afterward.
  // In some cases this may return no layer, in particular when the builder
  // was created by ContainerLayerBuilder::addContainerChild/addRenderedChild
  // (the layer system may have rendered the child's contents directly into the
  // parent).
  Layer finish();
};


class YUVLayerBuilder : LayerBuilder {
For scrolling and to enable intelligent reuse of parts of RenderedLayers by other layers...
  // Create a YUV layer with given size and format, and adopt the memory buffer
  YUVLayerBuilder(size, format, bufferToAdopt);
};


class WebGLBufferLayerBuilder : LayerBuilder {
==== ContainerLayer ====
  // Create a layer that's a logical copy (ideally copy on write) of the
  // underlying buffer managed by a WebGL canvas
  WebGLLayerBuilder(webGLBuffer);
};


  class ContainerLayerBuilder : LayerBuilder {
  class ContainerLayer {
  // format can be RGB, ARGB (eventually ARAGAB?).
  // This constructs a container layer that can be used anywhere.
  ContainerLayerBuilder(size, format);
  // The following methods can only be called after all LayerBuilder property
  // setters are done.
   // Add an existing layer
   // Add an existing layer
   addLayer(Layer);
   addLayer(Layer);
Line 191: Line 177:
   // done. The context cannot be used after finish() is called.
   // done. The context cannot be used after finish() is called.
   gfxContext* getContext();
   gfxContext* getContext();
};
class YUVLayerBuilder : LayerBuilder {
  // Create a YUV layer with given size and format, and adopt the memory buffer
  YUVLayerBuilder(size, format, bufferToAdopt);
};
class WebGLBufferLayerBuilder : LayerBuilder {
  // Create a layer that's a logical copy (ideally copy on write) of the
  // underlying buffer managed by a WebGL canvas
  WebGLLayerBuilder(webGLBuffer);
  };
  };


1,295

edits