Allocation module

The allocation module is a shared object that provides memory allocation and de-allocation services for graphic buffers. As memory allocation and destruction is tied to hardware, this module is platform-dependent and there are several implementations of the allocation module based on underlying hardware.
Note:
It's possible to use a software allocation module (e.g., screen-stdbuf.so), but buffers that are allocated with this module most likely wouldn't be usable by hardware. The software allocation module primarily serves as a reference implementation that platform-specific allocation modules can build on.

You can use the WFD driver or a separate allocator module to handle the allocation functionality. If both are available, Screen uses the allocator module. If neither of the allocations method are provided, Screen won't start.

The WFD driver can be an allocator if it defines the WFD_QNX_egl_images extension, which must provide the wfdDestroyWFDEGLImagesQNX() and wfdCreateWFDEGLImagesQNX() functions. The memory returns in the form of a win_image_t structure, which Screen server then wraps with a libmemobj object.

The allocator module is configured with the alloc-config parameter under the globals section of the configuration file. Screen server loads (using dlopen()) the allocation module that is specified in the configuration file, graphics.conf. Based on the interface used by the allocation module, the returned memory will be in a form of a libscrmem object with encapsulated libmemobj object or as a win_image_t structure, which Screen server then wraps with a libmemobj object.

In Screen server, all graphics buffer memory is encapsulated in a gbuf structure and all graphics buffer memory allocation requests have to go through the Graphics Buffer Management.

The following image illustrates the Screen architecture allocation module:

Functionality

The allocation module is responsible for the following:

Creating buffers

The allocation module creates a buffer based on the size, pixel format and usage that is specified.

The usage of the buffer is particularly important information for the allocation module to have. This usage can dictate how and where the allocation module allocates the buffer (e.g., from a specific memory pool and/or if the memory must be in a physically contiguous region).

Destroying buffers
The allocation module frees the memory that was allocated.
Importing and detaching external images specified as win_image_t
This is an optional functionality that enables Screen to import and attach then detach external provided graphics memory.

Interfaces

The complete allocator module interface is described in screen/alloc.h. The allocator module can be designed to either return allocated memory specified as a scrmem object (refer to the libscrmem library for specification) or as a win_image_t structure (defined in screen/iomsg.h).

Note:
When create_scrmem() is provided, Screen uses this method and doesn't load create_images() and destroy_images() implementations in the allocator module.

For details on import_image() and detach_images(), refer to screen/alloc.h.

The scrmem-based allocator

Screen expects the create_scrmem() function to be defined by the allocation module:

int (*create_scrmem)( int width,
                      int height,
                      int format,
                      int usage,
                      size_t count,
                      struct scrmem **scrmem );
Allocates a scrmem object, which consists of memobj and win_image_t. The following parameters specify the memory size and restrictions:
width
The width of the image buffer, in pixels.
height
The height of the image buffer, in pixels.
format
A 32-bit integer, with lower 16-bit representing enum of pixel formats defined in screen.h, and higher 16-bit representing platform-specific variant of the pixel format, if one present.
usage
A bitmask indicating the intended usage for the graphics buffer. Available values are defined in screen.h.
count
The number of buffers to create.
scrmem
A pointer to the array libscrmem objects (each buffer has its own scrmem object associated with it), which is returned to Graphics Buffer Management

The destructor for this memory is specified during scrmem creation; refer to the libscrmem description for additional information. The destructor definition comes from the allocate module and not the caller. When the graphics buffer is no longer required, the Graphics Buffer Management unmaps and deallocates the corresponding the gbuf object (i.e., when it's no longer used by another other process or thread).

Interface logic

  1. Determine the size of the buffer based on requested height, width, usage and format
  2. Determine appropriate memobj attributes, such as if the memory should be typed, physical contiguous, have special cache flags.
  3. For each buffer:

    1. If memory will be allocated by the libmemobj, create memobj with attributes (from step 2). If libmemobj needs to wrap memory: allocate/obtain required memory and either provide a shared-memory FD or vaddr to the libmemobj for wrapping. If libmemobj handle is wrapping an already allocated memory, then ensure that memory can be freed when it is no longer needed (memobj destructor can be used for this cleanup).
    2. Allocate and fill the win_image_t structure.
    3. Create a scrmem object with a memobj handle (from step 3a) and a win_image_t structure (from step 3b).
    4. Associate an appropriate destructor for the scrmem object. The destructor is part of the allocator design; it's responsible for cleaning up memory after the scrmem object is no longer required. At the very least, the destructor should free memory used by the win_image_t structure (allocated in step 3b) and close the memobj (from step 3a).

The win_image_t-based allocator

In this interface, the returned images are described by the win_image_t structure. Screen server wraps this information into a libmemobj object before encapsulating it with gbuf information. This interface requires both the create_images() and destroy_images() functions:

create_images()

int (*create_images)( int width,
                      int height,
                      int format,
                      int usage,
                      size_t count,
                      struct win_image **images );

The parameters include:

width
The width of the image buffer, in pixels.
height
The height of the image buffer, in pixels.
format
A 32-bit integer, with the lower 16-bits representing an enum of pixel formats defined in screen.h and the higher 16-bits representing a platform-specific variant of the pixel format, if present.
usage
A bitmask indicating the intended usage for the graphics buffer. Available values are defined in screen.h.
count
The number of buffers to create.
images
A pointer used to return the allocated buffer.

destroy_images()

int (*destroy_images)( size_t count,
                       struct win_image **images );

The parameters include:

count
The number of buffers to destroy.
images
A pointer to the buffer location.

The WFD allocator

The WFD_QNX_egl_images extension

This interface is not a stand-alone module, but is a part of the display's WFD driver, which must support the WFD_QNX_egl_images extension. The Screen server uses the driver associated with the display (SCREEN_PROPERTY_DISPLAY) for the window, stream, or pixmap objects that will own the buffers.

As with the create_images() and destroy_images() interfaces, the returned object is of win_image_t type. The Screen server wraps this allocation into a libmemobj object before encapsulating it with gbuf information.

Both wfdCreateWFDEGLImagesQNX() and wfdDestroyWFDEGLImagesQNX() are required parts for this interface; refer to WF/wfdext.h for more information.

Information on buffer creation

Special format bits
The top 16 bits of the image format, if non-zero, indicate a platform-specific variant of whatever format is associated with the lower 16 bits. For example, SCREEN_FORMAT_RGBA8888 has value 8; the format 0x30008 would have 8-bit R,G,B,A components, but might be tiled or have some other unusual memory layout. The caller can set these bits to request a specific format (if not possible, the call must fail). The allocator is also free to return a special format when not requested, if it does not conflict with the specified usage flags. In particular, the format must not be changed if READ and/or WRITE were requested.
Usage flags

The usage flags (SCREEN_USAGE_*) are described in the Screen usage flag types section of the Screen Graphics Subsystem Developer's Guide. A set of requested flags is passed to one of the above allocation APIs, which are expected to return an error if they don't support the combination of flags or failed to allocate for those purposes. On success, the returned win_image_t structures are expected to have all requested usages, but may have additional ones added if the allocator determines the buffers are suitable for other uses.

Note that these flags may be problematic for composition, including external composition, because there's no way to indicate which flags the compositor requires. Based on the expectations for the platform, the allocator may need to act as if certain flags are always present. For example, if the platform uses the gles compositor, all buffers will need to be suitable for the GPU driver.

SCREEN_USAGE_DISPLAY

If requested, memory that is directly displayable by the WFD driver is required, and the allocation request must fail if it is not available. Screen always requests this for framebuffers.

If not requested, the allocator should add the bit if the allocated memory happens to be displayable. For example, some display controllers require physically contiguous memory, and the OS will often provide contiguous memory even when not specifically requested.

SCREEN_USAGE_OVERLAY
When requested, this implies SCREEN_USAGE_DISPLAY. An allocator shouldn't add this bit if not requested. It is intended more to change Screen's behavior than the allocator's.
SCREEN_USAGE_READ, SCREEN_USAGE_WRITE
If either of these usages are requested, the client expects to receive memory in the exact layout they requested. The allocator cannot substitute a special format in this case.
SCREEN_USAGE_NATIVE
This indicates the buffer must be usable as a source or destination (ideally both) for the platform's native blitter. If that is gles2blt, the flag is basically equivalent to SCREEN_USAGE_OPENGL_ES2.
SCREEN_USAGE_VIDEO
On some platforms, this implies suitability for a hardware video encoder/decoder.
SCREEN_USAGE_CAPTURE
This means the platform's video capture library can capture data into the buffer.
SCREEN_USAGE_ROTATION
If set, the allocator needs to fill strides[1] in the returned win_image_t structures. Screen swaps the strides when rotating the buffer (the size, offset, and pointers remain the same).
Typed memory pool
On some hardware platforms, the memory has to be allocated from a typed-memory pool. This pool can be specified with the alloc-pool setting in the globals section of the graphics.conf file.
Rotation
The support for rotation is hardware-depended. On the systems with rotation support, the allocation module will allocate addition memory for the buffer with SCREEN_USAGE_ROTATION. If WFD doesn't support rotation, the Screen server allocates additional graphic's buffers to perform rotation during composition.

Dependencies

In Screen, the allocation module is dependent on libmemobj and libscrmem . As this is a platform-depended module, it might also depend on hardware-specific software modules, which are outside of Screen implementation.

Error handling

The allocation module returns an error code. Some possible error values are defined by POSIX while others are defined by QNX. Refer to the QNX OS C Library Reference for details. When the request for buffer creation is not successful, no memory is allocated; the allocation module cleans up any memory that it may have allocated in the process of processing this request.

Memory usage

The memory required by the module’s operation is considered negligible.

The allocation module is platform-dependent. Therefore, it can impose its own behavior (e.g., tiler memory). Memory allocation may be from specific areas of the system's RAM or external memory. Typically, the system's RAM is not usable to graphics hardware.

Some platforms require contiguous system RAM for buffer allocations. In this case, the allocation module may be sensitive to physical RAM fragmentation and chooses to pre-allocate RAM at startup to mitigate the issue of fragmentation.

Many GPUs operate in units that are larger than one pixel. For example, a 1x1 buffer must be rounded up to 4x4 or 128x128 based on your platform and hardware constraints. In this case, the allocation module must adjust input parameters to adhere to hardware constraints or to enable acceleration features. The allocation module may allocate a buffer that is a multiple of the requested size in the cases when the GPU requires an auxiliary buffer that's in a different format.

Page updated: