Name NV_sync Name Strings EGL_NV_sync Contributors Gary King Gregory Prisament Acorn Pooley Jon Leech Contacts Acorn Pooley, NVIDIA Corporation (apooley 'at' nvidia.com) Gary King, NVIDIA Corporation (gking 'at' nvidia.com) Status Complete Version Version 7, July 27, 2010 Number EGL Extension #19 Dependencies Requires EGL 1.1 This extension is written against the wording of the EGL 1.2 Specification. Overview This extension introduces the concept of "sync objects" into EGL. Sync objects are a synchronization primitive, representing events whose completion can be tested or waited upon. This extension borrows heavily from the GL_ARB_sync extension, and like that extension, introduces only a single type of sync object, the "fence sync object." Additional types of sync objects may be introduced in later extensions. Fence sync objects have corresponding fences, which are inserted into client API command streams. A sync object can be queried for a given condition, such as completion of the corresponding fence. Fence completion allows applications to request a partial Finish of an API command stream, wherein all commands issued in a particular client API context will be forced to complete before control is returned to the calling thread. This extension is nearly identical to NVIDIA's original proposal for the EGL_KHR_sync extension, which some minor differences outlined in Issue 7 below. New Types /* * EGLSyncNV is an opaque handle to an EGL sync object */ typedef void* EGLSyncNV; /* * EGLTimeNV is a 64-bit unsigned integer representing intervals in * nanoseconds (unadjusted standard time). A type defined in the * standard Khronos header is used instead of * a less-portable native C type. */ #include typedef khronos_utime_nanoseconds_t EGLTimeNV; New Procedures and Functions EGLSyncNV eglCreateFenceSyncNV( EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list ); EGLBoolean eglDestroySyncNV( EGLSyncNV sync ); EGLBoolean eglFenceNV( EGLSyncNV sync ); EGLint eglClientWaitSyncNV( EGLSyncNV sync, EGLint flags, EGLTimeNV timeout ); EGLBoolean eglSignalSyncNV( EGLSyncNV sync, EGLenum mode ); EGLBoolean eglGetSyncAttribNV( EGLSyncNV sync, EGLint attribute, EGLint *value ); New Tokens Accepted in the parameter of eglCreateFenceSyncNV, and returned in when eglGetSyncAttribNV is called with EGL_SYNC_CONDITION_NV: EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6 Accepted as an attribute name in the parameter of eglCreateFenceSyncNV, and by the parameter of eglGetSyncAttribNV: EGL_SYNC_STATUS_NV 0x30E7 Accepted as an attribute value in the parameter of eglCreateFenceSyncNV for the EGL_SYNC_STATUS_NV attribute, by the parameter of eglSignalSyncNV and returned in when eglGetSyncAttribNV is called with EGL_SYNC_STATUS_NV: EGL_SIGNALED_NV 0x30E8 EGL_UNSIGNALED_NV 0x30E9 Accepted in the parameter of eglClientWaitSyncNV: EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001 Accepted in the parameter of eglClientWaitSyncNV: EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull Returned by eglClientWaitSyncNV: EGL_ALREADY_SIGNALED_NV 0x30EA EGL_TIMEOUT_EXPIRED_NV 0x30EB EGL_CONDITION_SATISFIED_NV 0x30EC Accepted in the parameter of eglGetSyncAttribNV: EGL_SYNC_TYPE_NV 0x30ED EGL_SYNC_CONDITION_NV 0x30EE Returned in when eglGetSyncAttribNV is called with EGL_SYNC_TYPE_NV: EGL_SYNC_FENCE_NV 0x30EF Returned by eglCreateFenceSyncNV in the event of an error: EGL_NO_SYNC_NV ((EGLSyncNV)0) Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) Add a new subsection at the end of Section 3.8, page 43 (Synchronization Primitives) "3.8.1 Sync Objects In addition to the aforementioned synchronization functions, which provide an efficient means of serializing client and native API operations within a thread, "Sync Objects" are provided to enable synchronization of client API operations between threads and/or between API contexts. Sync objects may be tested or waited upon by application threads. Sync objects have a status with two possible states: and . Events may be associated with a sync object. When an event is initially associated with a sync object, the object is unsignaled (its status is set to unsignaled). Once a sync object has been created, EGL may be asked to wait for a sync object to become signaled. Sync objects may also be signaled or unsignaled explicitly. Sync objects are associated with an EGLDisplay; this association is made when the sync object is created. Only one type of sync object is defined, the fence sync object, whose associated events are triggered by fence commands which are inserted into the command streams of client API contexts. Fence sync objects may be used to wait for partial completion of a client API command stream, as a more flexible form of glFinish / vgFinish. The command EGLSyncNV eglCreateFenceSyncNV( EGLDisplay dpy, enum condition, EGLint *attrib_list ); creates a fence sync object for the specified display and returns a handle to the new object. The sync object is assigned a type of EGL_SYNC_FENCE_NV. must be EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV. is an attribute-value list specifying other attributes of the sync object, terminated by an attribute entry EGL_NONE. Attributes not specified in the list will be assigned their default values. Attributes accepted by fence sync objects are listed in table 3.aa Attribute Name Attribute Value(s) Default Value --------------- ------------------------------------ -------------- EGL_SYNC_STATUS_NV EGL_SIGNALED_NV, EGL_UNSIGNALED_NV EGL_SIGNALED_NV Table 3.aa Fence Sync Object Attributes * If is not the name of a valid, initialized EGLDisplay, EGL_NO_SYNC_NV is returned and an EGL_BAD_DISPLAY error is generated. * If is not EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV, EGL_NO_SYNC_NV is returned and an EGL_BAD_PARAMETER error is generated. * If any attribute not appearing in table 3.?? is specified in , EGL_NO_SYNC_NV is returned and an EGL_BAD_ATTRIBUTE error is generated. The command EGLBoolean eglFenceNV( EGLSyncNV sync ); inserts a fence command into the command stream of the bound API's current context (i.e., the context returned by eglGetCurrentContext), and assoicates it with sync object . must be a sync object created with eglCreateFenceSyncNV, and the display associated with must match the current display (i.e., the display returned by eglGetCurrentDisplay). Calling eglFenceNV unsignals . When the condition of is satisfied by the fence command, is signaled by the associated client API context, causing any eglClientWaitSyncNV commands (see below) blocking on to unblock. The condition EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV is satisfied by completion of the fence command corresponding to the sync object, and all preceding commands in the associated client API context's command stream. will not be signaled until all effects from these commands on the client API's internal and framebuffer state are fully realized. No other state is affected by execution of the fence command. Multiple fence commands may be inserted in any client API command stream for a single sync object. The sync object is unsignaled every time a new fence command is issued, and signaled every time a previous fence command completes, so its status is indeterminate until all fence commands associated with the sync object have completed. However, each time a fence command completes (signaling the sync object), at least one eglClientWaitSyncNV command blocking on that sync object will unblock. EGL_TRUE is returned upon successful insertion of the fence command. * If is not a valid sync object with a type of EGL_SYNC_FENCE_NV, EGL_FALSE is returned and an EGL_BAD_PARAMETER error is generated. * If the display associated with does not match the current display, EGL_FALSE is returned and an EGL_BAD_MATCH error is generated. * If no context is current for the bound API (i.e., eglGetCurrentContext returns EGL_NO_CONTEXT), EGL_FALSE is returned and an EGL_BAD_MATCH error is generated. The command EGLint eglClientWaitSyncNV( EGLSyncNV sync, uint flags, EGLTimeNV timeout ); blocks the calling thread until the specified sync object is signaled, or until a specified timeout value expires. If is signaled at the time eglClientWaitSyncNV is called then eglClientWaitSyncNV will not block. If is unsignaled at the time eglClientWaitSyncNV is called then eglClientWaitSyncNV will wait up to nanoseconds for to become signaled. If the value of is zero, then eglClientWaitSyncNV will never block and simply tests the current status of . If the value of is the special value EGL_FOREVER_NV then eglClientWaitSyncNV does not time out. eglClientWaitSyncNV returns one of three status values describing the reason for returning. A return value of EGL_ALREADY_SIGNALED_NV will always be returned if was signaled when eglClientWaitSyncNV was called, even if is zero. A return value of EGL_TIMEOUT_EXPIRED_NV indicates that indicates that the specified timeout period expired before was signaled. A return value of EGL_CONDITION_SATISFIED_NV indicates that was signaled before the timeout expired. Note that a fence sync object can be in the signaled state because one of three events has occured: 1. A previously inserte fence has completed and has signaled the sync object. 2. The sync object was created. Creation of a sync object sets it in the signaled state by default, unless the attribute EGL_SYNC_STATUS_NV is set to EGL_UNSIGNALED_NV in the attribute list. 3. The sync object was signaled by a previously issued eglSignalSyncNV(sync, EGL_SIGNALED_NV) command. If the sync object being blocked upon will not be signaled in finite time (for example, by an associated fence command issued previously, but not yet flushed to the graphics pipeline), then eglClientWaitSyncNV may wait forever. To help prevent this behavior (footnote1), if the EGL_SYNC_FLUSH_COMMANDS_BIT_NV bit is set in , and is unsignaled when eglClientWaitSyncNV is called, then the equivalent of Flush() will be performed for the current API context (i.e., the context returned by eglGetCurrentContext()) before blocking on . If no context is current for the bound API, the EGL_SYNC_FLUSH_COMMANDS_BIT_NV bit is ignored. (footnote 1): The simple Flush behavior defined by EGL_SYNC_FLUSH_COMMANDS_BIT_NV will not help when waiting for a fence command issued in a different context's command stream. Applications which block on a fence sync object must take additional steps to ensure that the context from which the associated fence command was issued has flushed that command to the graphics pipeline. If a sync object is deleted when an eglClientWaitSyncNV is blocking on that object, the behavior of eglClientWaitSyncNV is undefined. Some possible behaviors are to return immediately, to wait for fence commands associated with the deleted sync to complete, or to not return until the timeout period expires. * If is not a valid sync object, EGL_FALSE is returned and an EGL_BAD_PARAMETER error is generated. The command EGLBoolean eglSignalSyncNV( EGLSyncNV sync, enum mode ); signals or unsignals the sync object by changing its status to , which must be one of the values in table 3.bb. If, as a result of calling eglSignalSyncNV, the status of transitions from unsignaled to signaled, then at least one eglClientWaitSyncNV commands blocking on will unblock. Assuming no errors are generated, EGL_TRUE is returned. Mode Effect ------------------ ------------- EGL_SIGNALED_NV Set the status of to signaled EGL_UNSIGNALED_NV Set the status of to unsignaled Table 3.bb Modes Accepted by eglSignalSyncNV Command * If is not a valid sync object, EGL_FALSE is returned and an EGL_BAD_PARAMETER error is generated. The command EGLBoolean eglGetSyncAttribNV( EGLSyncNV sync, EGLint attribute, EGLint *value ); is used to query attributes of the sync object . Legal values for depend on the type of sync object; these are listed in table 3.cc. Assuming no errors are generated, EGL_TRUE is returned and the value of the queried attribute is returned in . Attribute Description Supported Sync Objects ----------------- ----------------------- --------------------- EGL_SYNC_TYPE_NV Type of the sync object All EGL_SYNC_STATUS_NV Status of the sync object All EGL_SYNC_CONDITION_NV Signaling condition EGL_SYNC_FENCE_NV * If is not a valid sync object, EGL_FALSE is returned and an EGL_BAD_PARAMETER error is generated. The command EGLBoolean eglDestroySyncNV( EGLSyncNV sync ); is used to destroy an existing sync object. If any eglClientWaitSyncNV commands are blocking on when eglDestroySyncNV is called, their behavior is undefined. After calling eglDestroySyncNV, is no longer a valid sync object. Assuming no errors are generated, EGL_TRUE is returned. * If is not a valid sync object, EGL_FALSE is returned and an EGL_BAD_PARAMETER error is generated. Issues 1. Explain the key choices made in this extension. RESPONSE: This extension has been written to enable adoption to be as wide as possible, and to behave as similarly as possible to synchronization primitives available in desktop OpenGL (e.g., NV_fence, ARB_sync). In the interest of enabling widespread adoption, this extension (following the ARB_sync model) has foregone the inclusion of synchronization primitives and synchronization tests which may be performed entirely inside client API command streams, instead performing synchronization tests (eglClientWaitSyncNV) inside the application & host CPU. In the interest of maintaining similarity with previous synchronization primitives, this extension attempts to copy the ARB_sync specification wherever possible (both functionally and stylistically), only making changes where needed to operate inside EGL (rather than a client API context) and match EGL naming conventions. 2. Why place this behavior in EGL, rather than in the client APIs? RESPONSE: Ultimately, synchronization between multiple asynchronous client API contexts (potentially executing in different threads) is a problem which affects or will affect all EGL client APIs. Rather than creating separate synchronization primitives in each of the client APIs (and then wrapping them in an EGL container), in the interest of developer simplicity & consistency this behavior is being placed inside EGL. 3. What does this extension provide that can not be accomplished with the existing, more efficient eglWaitClient and eglWaitNative API functions? RESPONSE: eglWaitClient and eglWaitNative may be implemented in extremely lightweight manners, in some cases not blocking the calling thread at all; however, they can not be used to synchronize between client API contexts and native APIs executing in separate threads (or simply between client API contexts executing in separate threads), such as between a thread with an active OpenGL context and a second thread performing video decode. 4. What does this extension provide that could not be accomplished with native platform synchronization primitives and the existing client API Finish commands? RESPONSE: This extension provides a lighter-weight mechanism for synchronizing an application with client API command streams than the all-or-nothing Finish commands, enabling applications to block until a subset of issued client API commands have completed. 5. Should integration with native platform synchronization objects be included in this extension, or reserved for future (platform-specific) extensions? RESOLVED: Integration with native platform synchronization objects should not be part of this extension, but can be added as future layered extensions if needed. These layered extensions can be platform-specific, or perhaps OpenKODE based. Originally, this extension included the ability to create native platform synchronization objects from EGLSync objects. This feature was removed for a few reasons: i) The proposed mechanism suggested mapping EGLSync objects to pthread conditional variables on platforms with pthread support. However, pthread conditional variables require an associated mutex and there was no mechanism to relay this associated mutex to the application. ii) On certain platforms support for converting to native platform synchronization objects adds great complexity to the implementation. iii) Now that OpenKODE is more mature, it would be better to allow conversion from EGLSyncNV objects to OpenKODE synchronization primitives rather than platform-specific ones. We suggest that this functionality, if needed, be added as a layered extension instead of being included here. This way, EGL_NV_sync remains minimal and easy to implement on a variety of platforms. 6. Please provide a more detailed description of how ClientWaitSyncNV behaves. RESPONSE: Issue 18 in the ARB_sync specification includes a very detailed description of ClientWaitSyncARB (the ARB_sync equivalent of ClientWaitSyncNV). This is provided (unmodified) below: Does ClientWaitSyncARB wait on an event, or on sync object status? What is the meaning of sync object status? RESOLVED: ClientWaitSyncARB blocks until the status of the sync object transitions to the signaled state. Sync object status is either signaled or unsignaled. More detailed rules describing signalling follow (these need to be imbedded into the actual spec language): R1) A sync object has two possible status values: signaled or unsignaled (corresponding to SYNC_STATUS_ARB values of SIGNALED_ARB or UNSIGNALED_ARB, respectively). R2) When created, the state of the sync object is signaled by default, but may be explicitly set to unsignaled. R3) A fence command is inserted into a command stream. A sync object is not. R4) When a fence command is inserted into a command stream using FenceARB(), the status of the sync object associated with that fence command is set to the unsignaled state. R5) Multiple fence commands can be associated with the same sync object. R6) A fence command, once its condition has been met, will set its associated sync object to the signaled state. The only condition currently supported is SYNC_PRIOR_COMMANDS_COMPLETE_ARB. R7) A wait function, such as ClientWaitSyncARB, waits on a sync object, not on a fence. R8) A wait function, such as ClientWaitSyncARB, called on a sync object in the unsignaled state will block. It unblocks (note, not "returns to the application") when the sync object transitions to the signaled state. Some of the behaviors resulting from these rules are: B1) Calling ClientWaitSyncARB with a timeout of 0 will return TRUE if the sync object is in the signaled state. Note that calling ClientWaitSyncARB with a timeout of 0 in a loop can miss state transitions. B2) Stacking fences is allowed. Each fence, once its condition has been met, will set its associated sync object to the signaled state. If the sync object is already in the signaled state, it stays in that state. B3) ClientWaitSyncARB could take a timeout parameter and return a boolean. If the timeout period has expired, ClientWaitSyncARB will unblock and return FALSE to the caller. If ClientWaitSyncARB unblocks because the sync object it was waiting on is in the signaled state, it will return TRUE. B4) We could define a FinishMultipleSync() command that will unblock once all (or any) of the sync objects passed to it are in the signaled state (also see issue 12). B5) We could define a set/resetSyncObject function to manually set the sync object in the signaled or unsignaled state. This makes it easy for apps to reuse a sync object in the multi-context case, so the sync object can be blocked upon before a fence command is associated with it in the command stream. B6) We could define an API to convert a sync object into an OS specific synchronization primitive (Events on Windows, file descriptors or X-events or semaphores on Unix?) 7) How does this extension differ from (relate to) EGL_KHR_sync: RESPONSE: As of the time of writing this, the EGL_KHR_sync specification has not been finalized by Khronos and continues to undergo revision. However, NVIDIA has the functionality outlined in this specification implemented and has decided to make it available to developers immediately. For the most part, EGL_KHR_sync is identical to revision 5 of EGL_KHR_sync with the following changes: a) Enum values are different b) EGLTimeNV is unsigned long long instead of uint64_t. c) Behaviour when there are multiple waiting threads is undefined. Revision History #7 (Jon Leech, July 27, 2010) - Redefine EGLTimeNV type to use a typedef from the standard Khronos headers instead of a native C type, for portability. #6 (Greg Prisament, May 28, 2009) - Branch spec & turn it into an _NV extension. #5 (Greg Prisament, July 22, 2008) - Removed NativeSyncKHR, CreateNativeSyncKHR, and corresponding wording. - Correct EGLuint to EGLint (EGLuint doesn't exist). #4 (Jon Leech, November 20, 2007) - Corrected 'enum' to 'EGLenum' in prototypes. #3 (Jon Leech, April 5, 2007) - Added draft Status and TBD Number #2 (November 27, 2006) - Changed OES token to KHR