3.0 Porting Guide/Graphics and UI/OpenGL

From Tizen Wiki
Jump to: navigation, search

This document describes the essential elements of Tizen's platform-level graphics architecture related to OpenGL ES and EGL, and how it is used by the application framework and the display server. The focus is on how graphical data buffers move through the system.

Tizen platform requires the OpenGL ES driver for the acceleration of the Wayland display server and wayland-egl client. This platform demands OpenGL ES and EGL driver which is implemented by the Tizen EGL Porting Layer.

Tizen OpenGL ES and EGL Architecture

The following figure illustrates the Tizen OpenGL ES and EGL architecture.

OPENGLES STACK.png
CoreGL

An injection layer of OpenGL ES that provides the following capabilities:

  • Support for driver-independent optimization (FastPath)
  • EGL/OpenGL ES debugging
  • Performance logging
  • Supported versions
    • EGL 1.4
    • OpenGL ES 1.1, 2.0, 3.0, 3.1

CoreGL loads the manufacturer's OpenGL ES driver from the /usr/lib/driver directory. CoreGL provides the libEGL.so, libGLESv1_CM.so, and libGLESvs.so driver files in the /usr/lib directory.

GPU Vendor GL / EGL driver

The Tizen platform demands that the GPU vendor implements the GL and EGL driver using libtpl-egl. The GPU vendor GL / EGL driver must be installed in the following path:

Library path File
/usr/lib/driver libEGL.so

libGLESv1_CM.so

libGLESv2.so

Tizen Porting Layer (TPL) for EGL

TPL-EGL is an abstraction layer for surface and buffer management on Tizen platform. It is used for implementation of the EGL platform functions.

Tpl architecture.png

The background for the Tizen EGL Porting Layer for EGL is in various window system protocols in Tizen. There was a need for separating common layer and backend.

Tizen uses the Tizen Porting Layer for EGL, as the TPL-EGL APIs prevents burdens of the EGL porting on various window system protocols. The GPU GL Driver’s Window System Porting Layer can be implemented by TPL-EGL APIs which are the corresponding window system APIs. The TBM, Wayland, and GBM backends are supported.

Tizen Porting Layer for EGL Object Model

TPL-EGL provides interfaces based of object driven model. Every TPL-EGL object can be represented as a generic tpl_object_t, which is reference-counted and provides common functions. Currently, display and surface types of TPL-EGL objects are provided. Display, like normal display, represents a display system which is usually used for connection to the server. Surface corresponds to a native surface like wl_surface. A surface might be configured to use N-buffers, but is usually double-buffered or triple-buffered. Buffer is actually something to render on, usually a set of pixels or a block of memory. For these 2 objects, the Wayland, GBM, TBM backend are defined, and they are corresponding to their own window systems. This means that you do not need to care about the window systems.


TPL-EGL Core Object

TPL-EGL Object

Base class for all TPL-EGL objects

TPL-EGL Display

Encapsulates the native display object (Display *, wl_display) Like a normal display, represents a display system which is usually used for connection to the server, scope for other objects.

TPL-EGL Surface

Encapsulates the native drawable object (Window, Pixmap, wl_surface) The surface corresponds to a native surface, such as tbm_surface_queue or wl_surface. A surface can be configured to use N-buffers, but they are usually double-buffered or triple-buffered.


TPL-EGL Objects and Corresponding EGL Objects

Both TPL-EGL and vendor GLES/EGL driver handles the tbm_surface as TPL surface's corresponding buffer. It is represented by the TBM_Surface part in the following figure.

Relationship TPL EGL Gray.png

The following figure illustrates the GLES drawing API flow.

GLES API FLOW GRAY.png


TPL-EGL Frontend API

TPL-EGL Object

This is the base class for all TPL-EGL objects. It provides common functionalities to all TPL-EGL objects.

Function Description
tpl_object_reference() Increases the reference count of a TPL-EGL object. All TPL-EGL objects are reference-counted. They have reference count 1 on creatation. When the reference count drops to 0, the object is freed.
tpl_object_unreference() Decreases the reference count and destroys the object if it becomes 0.
tpl_object_get_reference() Gets the reference count of the given TPL-EGL object.
tpl_object_get_type() Gets the type of the object (display, surface, or buffer).
tpl_object_set_user_data() Sets the user data to a TPL-EGL object. Users want to relate some data with a TPL-EGL object. This function provides registering a pointer to such data which can be retrieved later using the tpl_object_get_user_data() function. The key is the pointer value itself as a key.
tpl_object_get_user_data() Gets the registered user data of a TPL-EGL object.

The object type is as follows, and each object is defined when it is created.

typedef enum {
    TPL_BACKEND_ERROR = -1,
    TPL_OBJECT_DISPLAY,
    TPL_OBJECT_SURFACE,
    TPL_BACKEND_MAX
} tpl_object_type_t;


TPL-EGL Display

Encapsulates the native display object (Display *, wl_display). Any other objects created from TPL-EGL Display inherit its backend type.

Function Description
tpl_display_create()
  • Creates the TPL-EGL display object for the given native display. Creates a TPL-EGL display if there is no existing TPL-EGL display for the given native display. If given NULL for native_dpy, this function returns the default display.
  • It must be called at least once at the eglInitialize time. This function must be called before calling tpl_display_get(), and the same TPL-EGL display will be returned if this function is called multiple times with one native_dpy.
  • In this function, the backend of TPL-EGL display corresponding to tpl_backend_type is initialized.
  • If type is TPL_BACKEND_UNKNOWN, it finds the backend for native_dpy and sets it.
  • The ref count of the newly created TPL-EGL display object is '1', and is destroyed by calling tpl_object_unreference().
tpl_display_get() Gets the TPL-EGL display object for the given native_dpy. If there is an existing TPL-EGL display for the given native display, it returns the TPL-EGL display.
tpl_display_get_native_handle() Gets the native display handle which the given TPL-EGL display is created for.
tpl_display_query_config() Queries the supported pixel formats for the given TPL-EGL display. You might want to know what pixel formats are available on the given display. This function is used to query such available pixel formats. Give TPL_DONT_CARE to parameters for size values if any values are acceptable.
tpl_display_filter_config() Filters the configuration according to a given TPL-EGL display. This function modifies current config specific to the current given TPL-EGL display.
tpl_display_get_native_window_info() Queries information on the given native window.
tpl_display_get_native_pixmap_info() Queries information on the given native pixmap.
tpl_display_get_buffer_from_native_pixmap()
  • Gets the native buffer from the given native pixmap.
  • It can be used when the server needs to know the actual buffer from the client's resources.


TPL-EGL Surface

Encapsulates the native drawable object (Window, Pixmap, wl_surface). Its main features are retrieving the buffer for a frame and posting the surface to a screen.

Function Description
tpl_surface_create()
  • Creates a TPL-EGL surface, which type is tpl_surface_type, for the given native_wnd.
typedef enum {
    TPL_BACKEND_ERROR = -1,
    TPL_SURFACE_TYPE_WINDOW,
    TPL_SURFACE_TYPE_PIXMAP,
    TPL_BACKEND_MAX
} tpl_surface_type_t;
  • This function can be called from eglCreateWindowSurface or eglCreatePixmapSurface and should be called first among the APIs of TPL-EGL surface.
  • Obtain a backend that is active through TPL-EGL display and then perform a surface initializing on the same backend.
  • Wayland_egl backend, a tbm_surface_queue is created in the backend in the given format.
  • The ref count of the newly created TPL-EGL surface object is 1, and is destroyed by calling tpl_object_unreference().
tpl_surface_get_display() Gets the TPL-EGL display where the given TPL-EGL surface was created from.
tpl_surface_get_native_handle() Gets the native surface handle of the given TPL-EGL surface.
tpl_surface_get_type() Gets the type of the given TPL surface.
tpl_surface_get_size() Gets the current size of the given TPL-EGL surface. Size of a surface can change when a user resizes window or the server resizes it. TPL-EGL updates the size information every time when a buffer is queried using the tpl_surface_dequeue_buffer() function. Consider that there can still be mismatch between actual surface size and the cached one.
tpl_surface_validate()
  • Validates the current frame of the given TPL-EGL surface and determines if a new buffer should be obtained because tbm_surface_queue has been reset or whether the native_wnd has been resized.
  • If the return value of this function is TPL_TRUE, it means no update, and TPL_FALSE means that the update occurred.
  • Call this function before getting the actual final render target buffer. If the return value of this function is TPL_FALSE, you must call tpl_surface_dequeue_buffer() to get a new validate buffer.
  • Buffer returned after calling this function is guaranteed to be not changing.
tpl_surface_dequeue_buffer()
  • Dequeue the buffer of the current frame for the given TPL-EGL surface. This function returns buffer of the current frame and that type is tbm_surface_h.
  • The tbm_surface_queue is basically run with three tbm_surfaces, and the render finished buffer must be enqueued back to the tbm_surface_queue via tpl_surface_enqueue_buffer().
  • Each time this function is called, another idle tbm_surface is returned. If no more tbm_surfaces are available in the queue, wait until there is an available tbm_surface in this function. Depending on backend, communication with the server can be required.
  • Returned buffers are used for rendering the target to draw the current frame. Returned buffers are valid until the next tpl_surface_dequeue_buffer() function call.
  • If the tpl_surface_validate() function returns TPL_FALSE, the previously returned buffers must no longer be used. This function is called again before drawing, and it returns a valid buffer.
  • To ensure the life cycle of tbm_surface, this function internally increases the reference count of tbm_surface, but it is better to increase the ref count of tbm_surface returned by the caller of this function.
tpl_surface_enqueue_buffer()
  • Enqueues a given tbm_surface to the tbm_surface_queue.
  • The tbm_surface must be dequeued one, and it should be equeued in the dequeued order.
  • If the caller of this function increased the reference count of dequeued tbm_surface, caller should also decrease the reference count of tbm_surface after this function.
  • This function request to presenter to post a frame. Scheduling post calls on a separate thread is recommended.
  • Make sure this function is called exactly once for a frame.
tpl_surface_enqueue_buffer_with_damage()
  • Enqueues a given tbm_surface with region of damage.
  • Damage information is used for reducing number of pixels composited in the compositor. Setting the num_rects to 0 or rects to NULL means entire area is damaged.
  • This function request to presenter to post a frame. Scheduling post calls on a separate thread is recommended.
  • This function is identical with the tpl_surface_enqueue_buffer() function except for delivering the damage information for updating.
  • Make sure this function is called exactly once for a frame.
tpl_surface_set_post_interval() The frame interval ensures that only a single frame is posted within the specified vsync intervals. When a frame ends, the frame interval is set to the surface's current interval.
tpl_surface_get_post_interval() Get frame interval of the given TPL-EGL surface.

The following code snippet shows a simple example of the Tizen Porting Layer.

dpy = tpl_display_create(...);
sfc = tpl_surface_create(dpy, ...);

while (1)
{
    buf = tpl_surface_dequeue_buffer(sfc);

    /* Draw something */

    tpl_surface_enqueue_buffer(sfc, buf);
}

In the GPU vendor driver, the "Draw something" part is what the GPU frame builder does. TPL-EGL exposes the native platform buffer identifiers and managers so that the buffer can be used in other modules. Currently, dma_buf/DRM is supported for these of purposes. EGL porting layer calls TPL-EGL functions to do what it is requested, and gives the result to the GPU vendor driver. TPL-EGL does all the protocol dependent actions. Such protocol dependent part can be well-separated into TPL-EGL backends. Also, TPL-EGL backend can be configured at runtime. You can specify which type of backend to use when initializing a display object.

TPL-EGL and Wayland Server and Client

Libtpl-egl-module diagram.png

Tizen uses the wl_tbm protocol instead of wl_drm. The wl_tbm protocol is born for sharing the buffer(tbm_surface) between the wayland_client and wayland_server. Although the wayland_tbm_server_init and wayland_tbm_client_init pair is a role for the eglBindWaylandDisplayWL, the EGL driver is required to implement the entrypoints for the eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL as dummy. For more information, see https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec.

Buffer Flow Between the Wayland Server and GLES/EGL Driver

The following figure shows the buffer flow between wayland server and GLES/EGL Driver. And passed buffer's type is tbm_surface.

Libtpl-egl buffer flow.png

Project Git Repository

Project Repository Description
libtpl-egl platform/core/uifw/libtpl-egl Tizen Porting Layer for EGL
libtbm platform/core/uifw/libtbm The library for the Tizen Buffer Manager
coregl platform/core/uifw/coregl An injection layer of OpenGL ES / EGL
wayland-tbm platform/core/uifw/wayland-tbm Wayland tbm is a protocol for graphics memory management for Tizen
emulator-yagl platform/adaptation/emulator/emulator-yagl OpenGL ES / EGL driver for the emulator
tpl-novice platform/core/uifw/ws-testcase Novice test framework for TPL

libtpl-egl Reference Driver

The Emulator YAGL (OpenGLES / EGL driver for the emulator) and MESA (OpenGLES / EGL driver for the RPI3) are implemented by libtpl-egl.

The following commit explains how to port the driver with libtpl-egl from the traditional drm-based driver.

Test and Verify the OpenGL ES Driver

The Khronos OpenGL ES CTS supports the wayland-egl. libtpl-egl has a test case for the libtpl-egl. The ws-testcase's tpl-novice has sample code for the libtpl-egl.