Platform/GFX/Gralloc

From MozillaWiki
Jump to navigation Jump to search

Everything that we know, and everything that we'd like to know, about Gralloc.

What is Gralloc?

Gralloc is a type of shared memory that is also shared with the GPU. A Gralloc buffer can be written to directly by regular CPU code, but can also be used as an OpenGL texture.

Gralloc is part of Android, and is also part of B2G.

This is similar to the functionality provided by the EGL_lock_surface extension, but EGL_lock_surface is not widely supported on Android/B2G.

Gralloc buffers are represented by objects of the class android::GraphicBuffer. See ui/GraphicBuffer.h.

We only use Gralloc buffers on B2G at the moment, because the locking semantics of Gralloc buffers tend to vary a lot between GPU vendors, and on B2G we can currently at least assume that we only have to deal with Qualcomm drivers. However, this got standardized in Android 4.2. See below.

Allocation and lifetime of Gralloc buffers

How Gralloc buffers are created and refcounted (non Mozilla-specific)

The android::GraphicBuffer class is refcounted. It is meant to be used with Android Strong Pointers (android::sp). That's why you'll see a lot of

 android::sp<android::GraphicBuffer>.

That's in fact the right way (the only way) to hold on to a GraphicBuffer.

The GraphicBuffer constructors take a "usage" bitfield. We should always pass HW_TEXTURE there, as we always want to use gralloc buffers as the backing surface of OpenGL textures. We also want to pass the right SW_READ_ and SW_WRITE_ flags.

How we create Gralloc buffers

Most of out GraphicBuffer's are constructed by GrallocBufferActor::Create. This unconditionally uses SW_READ_OFTEN and SW_WRITE_OFTEN, which is probably bad at least for some use cases.

Out protocol to create GraphicBuffers is as follows. It's generally the content side that wants to create a new GraphicBuffer to draw to. It sends a message to the compositor side, which creates the Gralloc buffer and returns a serialized handle to it; then back to the content side, we receive the serialized handle and construct our own Gralloc buffer instance from it.

In more detail (this is from Vlad's wiki page):

Content side:

  • Entry point: PLayersTransactionChild::SendPGrallocBufferConstructor (generally called by ISurfaceAllocator::AllocGrallocBuffer).
  • This sends a synchronous IPC message to the compositor side.

Over to the compositor side:

  • The message is received and this comes in as a call to PLayerTransactionParent::AllocPGrallocBuffer, implemented in LayersTransactionParent.cpp.
  • This calls GrallocBufferActor::Create(...), which actually creates the GraphicBuffer* and a GrallocBufferActor* (The GrallocBufferActor contains a sp<GraphicBuffer> that references the newly-created GraphicBuffer*).
  • GrallocBufferActor::Create returns the GrallocBufferActor as a PGrallocBufferParent*, and the GraphicBuffer* as a MaybeMagicGrallocBufferHandle.
  • The GrallocBufferActor/PGrallocBufferParent* is added to the LayerTransactionParent's managed list.
  • The MaybeMagicGrallocBufferHandle is serialized for reply (sending back the fd that represents the GraphicBuffer) -- using code in ShadowLayerUtilsGralloc ParamTraits<MGBH>::Write.

Back to the content side:

  • After the sync IPC call, the child receives the MaybeMagicGrallocBufferHandle, using ShadowLayerUtilsGralloc.cpp's ParamTraits<MGBH>::Read.
  • Allocates empty GrallocBufferActor() to use a PGrallocBufferChild.
  • Sets the previously created GrallocBufferActor/PGrallocBufferChild's mGraphicBuffer to the newly-received sp<GraphicBuffer>.
  • The GrallocBufferActor/PGrallocBufferChild is added to the LayerTransactionChild's managed list.
  • A SurfaceDescriptorGralloc is created using the PGrallocBufferChild, and returned to the caller.

How we manage the lifetime of Gralloc buffers

As said above, what effectively controls the lifetime of gralloc buffers is reference counting, by means of android::sp pointers.

Most of our gralloc buffers are owned in this way by GrallocBufferActor's. The question then becomes, what controls the lifetime of GrallocBufferActors?

GrallocBufferActors are "managed" by IPDL-generated code. When they are created by the above-described protocol, as said above, they are added to the "managee lists" of the LayerTransactionParent on the compositor side, and of the LayerTransactionParent on the content side.

FIXME XXX QUESTION: what then decides when GrallocBufferActors are destroyed and removed from the managee lists?

Unresolved problems

We don't have a good way of passing the appropriate USAGE flags when creating gralloc buffers. In most cases, we shouldn't pass SW_READ_OFTEN. If the SyncFrontBufferToBackBuffer mechanism requires that, that's sad and we should try to fix it (by doing this copy on the GPU). In many cases, it also doesn't make sense to pass SW_WRITE_OFTEN --- that basically only makes sense for Thebes layers, and Canvas2D if not using SkiaGL, but that doesn't make any sense for WebGL, SkiaGL canvas, or video.

It sucks that when content wants a new gralloc buffer to draw to, it has to wait for all the synchronous IPC work described above. Could we get async gralloc buffer creation?

Gralloc buffers locking

The lock mechanisms used by Gralloc buffers (non Mozilla-specific)

Genlock

How we lock/unlock Gralloc buffers

Drawing to Gralloc buffers

Drawing from Gralloc buffers (binding to GL textures)

Unresolved problems