KHR_stream_producer_eglsurface

Name

KHR_stream_producer_eglsurface

Name Strings

EGL_KHR_stream_producer_eglsurface

Contributors

Acorn Pooley
Jamie Gennis
Marcus Lorentzon

Contacts

Acorn Pooley, NVIDIA  (apooley 'at' nvidia.com)

Notice

Copyright (c) 2011-2013 The Khronos Group Inc. Copyright terms at
    http://www.khronos.org/registry/speccopyright.html

Status

Complete.
Approved by the Khronos Board of Promoters on December 2, 2011.

Version

Version 11, June 18, 2012

Number

EGL Extension #34

Dependencies

Requires EGL 1.2.
Requires OpenGL ES 1.1 or OpenGL ES 2.0.

Requires the EGL_KHR_stream extension.

Overview

This extension allows an EGLSurface to be created as a producer of
images to an EGLStream.  Each call to eglSwapBuffers posts a new
image frame into the EGLStream.

New Procedures and Functions

EGLSurface eglCreateStreamProducerSurfaceKHR(
                    EGLDisplay dpy,
                    EGLConfig config,
                    EGLStreamKHR stream,
                    const EGLint *attrib_list)

New Tokens

Bit that can appear in the EGL_SURFACE_TYPE of an EGLConfig:

EGL_STREAM_BIT_KHR                         0x0800

Add a row to "Table 3.2: Types of surfaces supported by an EGLConfig" in the EGL spec, right after the EGL_PBUFFER_BIT row:

    EGL Token Name         Description
    --------------         --------------------------
    EGL_STREAM_BIT_KHR     EGLConfig supports streams

In the second paragraph of section "Other EGLConfig Attribute Description" in the EGL spec, replace EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT with EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT | EGL_STREAM_BIT_KHR and replace "…cannot be used to create a pbuffer or pixmap." with "…cannot be used to create a pbuffer, pixmap, or stream."

Replace section "3.10.3.1 No way to connect producer to EGLStream" in the EGL_KHR_stream extension with this:

3.10.3.1 Stream Surface Producer

Call

    EGLSurface eglCreateStreamProducerSurfaceKHR(
                    EGLDisplay dpy,
                    EGLConfig config,
                    EGLStreamKHR stream,
                    const EGLint *attrib_list)

to create an EGLSurface and connect it as the producer of
<stream>.

<attrib_list> specifies a list of attributes for <stream>. The
list has the same structure as described for eglChooseConfig. The
attributes EGL_WIDTH and EGL_HEIGHT must both be specified in the
<attrib_list>.

EGL_WIDTH and EGL_HEIGHT indicate the width and height
(respectively) of the images that makes up the stream.

The EGLSurface producer inserts an image frame into <stream> once
for each time it is passed to eglSwapBuffers().  The image frame
is inserted after the GL has finished previous rendering commands.
Refer to section "3.10.5 EGLStream operation" in the
EGL_KHR_stream extension specification for operation of the
EGLStream when an image frame is inserted into it.

If <stream> is not in the EGL_STREAM_STATE_EMPTY_KHR,
EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR, or
EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR when passed to
eglSwapBuffers(), then eglSwapBuffers will return EGL_FALSE and
generate an EGL_BAD_CURRENT_SURFACE error.

If the application would like to have the results of rendering
appear on the screen at a particular time then it must query the
value of EGL_CONSUMER_LATENCY_USEC_KHR after calling
eglCreateStreamProducerSurfaceKHR.  This is the estimated time that
will elapse between the time the image frame is inserted into the
EGLStream and the time that the image frame will appear to the
user.

The image frame is not inserted into the EGLStream until the GL
has finished rendering it.  Therefore predicting exactly when the
image frame will be inserted into the stream is nontrivial.

If it is critical that this frame of data reach the screen at a
particular point in time, then the application can
    - render the frame (using GL/GLES commands)
    - call glFinish (or use other synchronization techniques to
       ensure rendering has completed).
    - wait until the time that the frame should appear to the user
       MINUS the value of EGL_CONSUMER_LATENCY_USEC_KHR.
    - call eglSwapBuffers
This will allow the image frame to be inserted into the EGLStream
at the correct time ("Image Frame Intended Display Time" minus
"Consumer Latency") so that it will be displayed ("Image Frame
Actual Display Time" as close as possible to the desired time.

However, this will cause the GPU to operate in lockstep with the
CPU which can cause poor performance.  In most cases it will be
more important for the image frame to appear to the user "as soon
as possible" rather than at a specific point in time.  So in most
cases the application can ignore the value of
EGL_CONSUMER_LATENCY_USEC_KHR, not call glFinish, and not wait
before calling eglSwapBuffers.

On failure eglCreateStreamProducerSurfaceKHR returns EGL_NO_SURFACE
and generates an error.

    - EGL_BAD_PARAMETER if EGL_WIDTH is not specified or is specified
      with a value less than 1.

    - EGL_BAD_PARAMETER if EGL_HEIGHT is not specified or is specified
      with a value less than 1.

    - EGL_BAD_STATE_KHR is generated if <stream> is not in state
      EGL_STREAM_STATE_CONNECTING_KHR.

    - EGL_BAD_MATCH is generated if <config> does not have the
      EGL_STREAM_BIT_KHR set in EGL_SURFACE_TYPE.

    - EGL_BAD_MATCH is generated if the implementation is not able to
      convert color buffers described by <config> into image frames
      that are acceptable by the consumer that is connected to
      <stream>.

    - EGL_BAD_STREAM_KHR is generated if <stream> is not a valid
      EGLStream created for <dpy>.

    - EGL_BAD_DISPLAY is generated if <dpy> is not a valid,
      initialized EGLDisplay.

Add a section preceding "3.9.3 Posting Semantics" in the EGL specification:

3.9.x Posting to a Stream

To post the color buffer to an EGLStream with an EGLSurface
producer, call

    EGLBoolean eglSwapBuffers(
                        EGLDisplay dpy,
                        EGLSurface surface);

If <surface> is the producer of an EGLStream then the
contents of the color buffer are inserted as a new image frame
into the EGLStream.

When eglSwapBuffers returns the contents of the color buffer will
have been inserted into the EGLStream as described in section
"3.10.5 EGLStream operation" in the EGL_KHR_stream extension
specification, and the EGL_PRODUCER_FRAME_KHR attribute and
EGL_STREAM_STATE_KHR attribute values will reflect this.

The contents of the color buffer and all ancillary buffers are
always undefined after calling eglSwapBuffers.

eglSwapBuffers is never synchronized to a video frame when
<surface> is the producer for an EGLStream (it is as if the
swapinterval (set by eglSwapInterval, see below section "3.9.3
Posting Semantics") is 0).

It is implementation dependent whether eglSwapBuffers actually
waits for rendering to the color buffer to complete before
returning, but except for timing it must appear to the application
that all rendering to the EGLSurface (e.g. all previous gl
commands) completed before the image frame was inserted into the
EGLStream and eglSwapBuffers returned (as described below in
section "3.9.3 Posting Semantics").

Add to section "3.9.4 Posting Errors" in the EGL specification a new sentence as the 2nd to last sentence in the first paragraph:

If eglSwapBuffers is called and the EGLStream associated with
surface is no longer valid, an EGL_BAD_STREAM_KHR error is
generated.

Issues 1. How many image frame buffers should be used?

    DISCUSSION:
    - leave up to implementation?
    - leave up to producer?
    - need hints from consumer?
    - In practice 1, 2, and 3 buffers mean different semantics
      which are visible to both the producer and consumer.  Each
      may be useful.  I cannot think of a use for more than 3
      buffers for EGL_KHR_stream_surface.  (For a video producer
      more than 3 often does make sense, but that is a different
      extension.)

    One possibility: expose EGL_BUFFER_COUNT_KHR to application.

    It probably does not make sense to ever use more or less than
    3 buffers.  One that is the EGLSurface back buffer.  One that
    is waiting for the consumer to acquire.  And one that the
    consumer has acquired and is actively consuming.

    RESOLVED: remove the EGL_BUFFER_COUNT_KHR parameter and always
    use 3 buffers.  This attribute can be added back with a
    layered extension later if needed.

2.  How is the resolution (width/height) of image frames set?

    RESOLVED: The width and height are set with the required
    EGL_WIDTH and EGL_HEIGHT attributes.  These do not change for
    the life of <stream>.

3.  How is the image format, zbuffering, etc set?

    RESOLVED: These are all determined by the <config>.  These do
    not change for the life of <stream>.

4.  How does eglSwapBuffers act if there are already image frames
    in the EGLStream when it is called.

    RESOLVED: Frames are inserted into the EGLStream as described
    in section "3.10.5 EGLStream operation" in the EGL_KHR_stream
    extension specification.  In particular:

        If the value of EGL_STREAM_FIFO_LENGTH_KHR is 0 or if the
        EGL_KHR_stream_fifo extension is not supported then the
        new frame replaces any frames that already exist in the
        EGLStream.  If the consumer is already consuming a frame
        then it continues to consume that same frame, but the next
        time the consumer begins to consume a frame (e.g. the
        next time eglStreamConsumerAcquireKHR() is called for a
        gltexture consumer) the newly rendered image frame will be
        consumed.  (This is the standard behavior for ANY producer
        when EGL_STREAM_FIFO_LENGTH_KHR is 0, described as "mailbox
        mode").

        If the EGL_KHR_stream_fifo extension is supported and the
        value of EGL_STREAM_FIFO_LENGTH_KHR is greater than 0 then
        the newly rendered frame will be inserted into the
        EGLStream.  If the EGLStream is full (already contains
        EGL_STREAM_FIFO_LENGTH_KHR frames) then eglSwapBuffers
        will block until there is room in the fifo.  Note that
        this can deadlock if the consumer is running in the same
        thread as the producer since the consumer will never be
        able to consume a frame if the thread is blocked waiting
        for room in the fifo.  This fifo-related behavior is
        described in the EGL_KHR_stream_fifo specification (this
        behavior is not specific to this producer; it works the
        same for all producers and all consumers).

    All rendering commands must complete before the color
    buffer is inserted into the EGLStream, or at least this is how
    the behavior must appear to the application.

    To be precise: when eglSwapBuffers returns the rendering
    commands may or may not actually be complete, but the
    following must all be true:
        - The EGL_PRODUCER_FRAME_KHR value reflects the frame that
            was just swapped by eglSwapBuffers
        - The EGL_STREAM_STATE_KHR indicates that the image frame
            is available (i.e. its value is
            EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR)
        - In mailbox mode if the consumer consumes a new frame it
            will get this new frame (not an older frame).  (For
            example, with a EGL_NV_stream_consumer_gltexture
            consumer, a call to eglStreamConsumerAcquireKHR() will
            latch this new frame.)
        - In fifo mode (see EGL_KHR_stream_fifo extension) if the
            consumer consumes a new frame and all previous frames
            have been consumed it will get this new frame (not an
            older frame).  (For example, with a
            EGL_NV_stream_consumer_gltexture consumer, a call to
            eglStreamConsumerAcquireKHR() will latch this new
            frame.)
        - If a consumer consumes the swapped frame, all GL (and
            other API) commands called prior to eglSwapBuffers
            will take effect on the image frame before the
            consumer consumes it.  In other words, the consumer
            will never consume a partially rendered frame.  (For
            example, with EGL_NV_stream_consumer_gltexture
            consumer, if the app does this:
                eglSwapBuffers()               // swap the producer EGLSurface
                eglStreamConsumerAcquireKHR()  // acquire the swapped image
                glDrawArrays()                 // draw something using the texture
            then the texture used in the glDrawArrays() command
            will contain the image rendered by all gl (and/or
            other API) commands preceding the eglSwapBuffers call
            as if the app had called glFinish and/or eglWaitClient
            just before calling eglSwapBuffers (but note that this
            is implicit in eglSwapBuffers; the app does NOT need
            to actually call glFinish or any other synchronization
            functions in order to get this effect, and in fact
            explicitly calling glFinish and/or eglWaitClient there
            may significantly and negatively affect performance).)

Revision History

#11 (June 18. 2012) Acorn Pooley
    - Replace EGLStream with EGLStreamKHR in function prototypes.

#10 (June 15, 2012) Acorn Pooley
    - Fix eglCreateStreamProducerSurfaceKHR name (was missing KHR)

#9 (October 17, 2011) Acorn Pooley
    - Clarify issue 4

#8 (October 12, 2011) Acorn Pooley
    - remove interactions with EGL_KHR_stream_fifo extension (they
      are already decribed in that extension).

#7 (October 11, 2011) Acorn Pooley
    - Add issue 4
    - add changes to section 3.9 of the EGL spec to clarify
      eglSwapBuffer behavior

#6 (October 4, 2011) Acorn Pooley
    - Convert from an NV extension to a KHR extension

#5 (September 30, 2011) Acorn Pooley
    - Remove EGL_BUFFER_COUNT_NV (0x321D) attribute and resolve issue 1.

#4 (September 27, 2011) Acorn Pooley
    - Assign enum values (bug 8064)

#3 (July 6, 2011) Acorn Pooley
    - Rename EGL_KHR_image_stream to EGL_KHR_stream

#2  (June 30, 2011) Acorn Pooley
    - remove dependence on EGLImage
    - clarify overview
    - remove glossary (it can be seen in EGL_KHR_stream ext)
    - Add EGL_STREAM_BIT
    - clarify description
    - describe attribute

#1  (April 20, 2011) Acorn Pooley
    - initial draft

vim:ai:ts=4:sts=4:expandtab:textwidth=70