EGLDevice

This topic describes EGL mechanisms that you can use to render 3D images on a pure EGL display. Such a display does not use a window system.

EGLDevice

EGLDevice provides a mechanism to access graphics functionality in the absence of or without reference to a native window system. It is a method to initialize EGL displays and surfaces directly on top of GPUs/devices rather than native window system objects. It is a cross-platform method to discover media devices like displays, GPUs, etc. The set of EGLDevice extensions boot strap EGL, without the use of any native APIs.

EGLOutput

EGLOutput is to graphical outputs what EGLDevice is to devices. It allows enumeration of outputs on a device. EGLOutput allows rendering directly to a screen in the absence of a window system. Additionally, it allows applications to bypass native window systems for direct rendering. It defines certain EGL resources for referencing display control hardware associated with an EGL device. EGLOutput provides a binding between GL, NVIDIA® CUDA®, and multimedia rendering and the display output. In a typical Embedded setting, the outputs are often initialized to a fixed state at system startup. But in cases where they are configurable, other interfaces such as DRM must be used.

EGLStream

EGLStream is a mechanism to share data efficiently between different APIs without copying data. APIs could be OpenGL®, CUDA, Multimedia, etc. A producer and a consumer are attached to two ends of a stream object:

  • Producer adds content into the stream.

  • Consumer retrieves this content.

EGLOutput instances can also be specified as consumers, allowing APIs to direct their output to the screen.

Extensions

EGL extensions specify the behavior, procedures, and functions for these EGL mechanisms.

  • EGLDevice

    • EGL_EXT_device_base

    • EGL_EXT_platform_base

    • EGL_EXT_platform_device

  • EGLOutput

    • EGL_EXT_output_base

  • EGLStream

    • EGL_KHR_stream

    • EGL_KHR_stream_producer_eglsurface

    • EGL_EXT_stream_consumer_egloutput

For a description of these EGL extensions, see:

Runtime Configuration

The sections below describe runtime configurations.

Conditions Requiring a Stream Surface

In the absence of an underlying window system, the stream surface is necessary for on screen rendering. Stream surfaces behave like any other EGLSurface. For example, eglSwapBuffers() must still be called to indicate the end of a frame. However, stream surfaces are stream producers, so eglSwapBuffers() submits rendering to the stream rather than presenting it to a native window directly. Typically, an EGLOutput consumer can use any producer attached to the stream but needs a surface producer when rendering API is OpenGL. For more information, see Creating a Stream Surface.

A common use case for stream producer surfaces is an application producing display frames using OpenGL, attached as a producer to one end of an EGL stream. The stream consumer on the other end is an EGLOutput layer sending frames directly to a display device.

Implementation

The following two sub-sections describe the steps to render to an EGL device using a stream surface.

Rendering to EGLDevice

These are the steps to render to an EGL device (more detailed steps follow):

  1. Create an EGL display from an EGL device.

  2. Create an EGL context from the EGL display.

  3. Create an EGL stream producer surface.

  4. Bind a GL context to the stream surface, i.e. make current.

  5. Post the surface contents to the stream using swap buffers.

Creating a Stream Surface

Creating a stream surface uses the following functions:

Function

Extension and Function Description

eglCreateStreamProducerSurfaceKHR()

EGL_KHR_stream_producer_eglsurface

Creates an EGLSurface and connects it as the producer of a stream.

eglStreamConsumerOutputEXT()

EGL_EXT_stream_consumer_egloutput

Binds an EGLOutput layer as a stream consumer to send rendering directly to a display device.

According to the EGL_KHR_stream specification, the EGLStream cannot be used until it has been connected to a consumer and producer. The consumer must be connected before the producer is connected.

To render to an EGLDevice through stream

  1. Query EGL extensions with eglGetProcAddress().

  2. Query available EGLDevices with eglQueryDevicesEXT().

  3. Obtain an EGLDisplay from the EGLDevice with eglGetPlatformDisplayEXT().

    This step creates an EGLDisplay that does not belong to any native platform.

  4. Initialize EGL with eglInitialize().

  5. Set up an EGLOutput. For detailed steps, see Setting Up the Display with DRM.

    • Select an output.

      • Can be done by enumerating all outputs and selecting a known index.

      • Can be done by looking up an output associated with a native (e.g. DRM) screen handle.

    • If necessary, initialize display settings with native interfaces.

  6. Direct rendering to an EGLOutput.

    • Create an EGLStream with eglCreateStreamKHR().

    • Connect the output layer to the EGLStream. Bind consumer end of stream to EGLOutput window object with eglStreamConsumerOutputEXT().

  7. Set buffer configurations by choosing an EGLConfig.

  8. Create a stream producer surface to feed the EGLStream with eglCreateStreamProducerSurfaceKHR().

  9. Create an EGLContext and make it current by binding it to the stream surface with eglMakeCurrent().

  10. Post surface contents to the stream with eglSwapBuffers().

To use an EGLStream in cross-process mode

  1. Make the following additions and changes to nvm_eglstream.int:

    AddressSpace nvm_eglstream_producer
      Filename      nvm_eglstream_as0
      Arguments     -producer 0 -f /nfsmount/welcome_animation.264 -standalone 1
      MemoryPoolSize      32M
      ExtendedMemoryPoolSize    64M
      HeapExtensionReservedSize 64M
      Language      C
      Task        Initial
        StartIt     false
        StackLength   2M
      EndTask
    EndAddressSpace
    
    AddressSpace nvm_eglstream_consumer
      Filename      nvm_eglstream_as0
      Arguments     -consumer 0 -d 2 -standalone 2
      MemoryPoolSize      32M
      ExtendedMemoryPoolSize    64M
      HeapExtensionReservedSize 64M
      Language      C
      Task        Initial
        StartIt     false
        StackLength   2M
      EndTask
    EndAddressSpace
    
  2. Rebuild the application.

  3. Load the application binary with the following command:

    Load /nfsmount/nvm_eglstream_egldevice
    
  4. Start the consumer with the following command:

    rt nvm_eglstream_consumer Initial
    
  5. Start the producer with the following command:

    rt nvm_eglstream_producer Initial

    This procedure enables a video producer and video consumer combination. The same procedure can also be extended for other producer/consumer combinations.

Cross-Process and Cross-Partition EGLStream Applications

This release includes the simple cross-process EGLDevice consumer and producer applications helloconsumer and helloproducer. The applications listen on 127.0.0.1, port 8888 by default. They can be used as cross-partition applications by passing –-crosspart or -c to the consumer and –-crosspart [<consumer_ip>] or -c [<consumer_ip>] to the producer.

The applications are built into demo_dd.

To use the applications

  1. Load demo_dd.

  2. Start helloconsumer on the target with the following command:

    rt helloconsumer Initial
    
  3. Start helloproducer on the target with the following command:

    rt helloproducer Initial
    

If the applications run correctly, the upper-left corner of display 2 contains a flashing square.

Using EGL_KHR_stream_consumer_gltexture functionality, the EGLStream can also be bound to a gltexture consumer (requiring an EGLContext.) The consumer texture buffer can then be rendered to an EGLSurface, for example.

For more information, see the man page for EGL_KHR_stream_consumer_gltexture on the Khronos web site.

Connecting a Surface to a Screen

You must use an EGLStream to connect a surface (i.e., a stream surface) to a screen. The surface is the stream producer, and the screen is the stream consumer.

  • eglGetPlatformDisplayEXT() returns an EGLDisplay handle belonging to a screen as specified by platform argument in the function call.

  • eglMakeCurrent() attaches an EGL rendering context to draw and read an EGL surface. It also binds a context and a surface to the current rendering thread.

  • Steps 6 through 9 in Creating a Stream Surface are required for connecting a stream surface to a screen.

  • eglGetPlatformDisplayEXT() returns a handle to screen.

  • eglMakeCurrent() binds the handle to the current context and surface.

Setting Up the Display with DRM

The Direct Rendering Manager (DRM) is a framework to manage GPUs and displays. Managing connected monitors and displays and changing the current modes is called mode-setting and is one of the functions of DRM. As mentioned in the “If necessary, initialize display settings …” part in Step 5 in Creating a Stream Surface, this native interface can be used to initialize the display setting.

To select an encoder, CRTC, and connector

  1. Open a DRM device file with drmOpen().

  2. Obtain DRM-KMS resources with drmModeGetResources().

  3. (Optional) Get plane information with drmModeGetPlane() and drmModeGetPlaneResources().

  4. Query the desired connector with drmModeGetConnector().

    All valid modes for a connector can be retrieved with a call to drmModeGetConnector(). Select the mode to be used and save it. The first mode in the list is the default mode with the highest resolution possible and often a suitable choice.

  5. If there is already an encoder attached to the connector, choose it with drmModeGetEncoder().

    If the attached encoder is incompatible with CRTC/plane find another one by iterating over all available encoders.

  6. Select a suitable CRTC.

    • For each connector, find a CRTC to drive this connector. To find a suitable CRTC, iterate over the list of encoders that are available for each connector. Each encoder contains a list of CRTCs that it can work with and select one of these CRTCs.

  • Query info for CRTC with drmModeGetCrtc().

  1. If necessary, set the mode with drmModeSetCrtc(). Obtain the layer for the plane/CRTC.

    Use CRTC to drive the selected connector with a call to drmModeSetCrtc().

  2. If a plane must be used, set it with drmModeSetPlane().

More information

  • For API details, see “DRM API” in NVIDIA Jetson Linux API Reference.

  • Ask your NVIDIA Customer Engineer for a sample implementation, window_egldevice.zip.

Board-to-Display Connectors

For information about the connectors on your platform and the relationship between connectors and displays, see the documentation for your hardware.