-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Visibility of changes to targets created from EGLImages is underspecified #566
Comments
@stonesthrow Any thoughts on this? |
I don't think some of the language got into the EGL specification from the original extensions. Check the original extension specs: With images, no copies of the buffer are made (unless re-specification) so its all sharing the same buffer. So anything that draws to it is semi-immediate, however, a synchronization/fence should be used by application/user to ensure the draw is complete, there is no inherent flush, before underlying buffer is used somewhere else. Although Piers can confirm on rebinding that a flush is complete. In your scenario, a fence should be inserted after rendering and waited by the sampling context. |
@stonesthrow, by fence to you mean an EGLSync as specified in EGL_KHR_fence_sync/EGL 1.5? From the KHR spec, speaking in regards to fence sync objects:
Which I believe is trying to say the effects are visible, so I would agree with your interpretation. Texture and memory barrier commands do not seem relevant from my interpretation of their definition. They merely order specific types of memory accesses relevant to each other within a given context. That may have the desired side effects on an EGLImage content's visibility external to that context, but it doesn't seem guaranteed. Fences are the only thing that explicitly operate across context boundaries from what I can tell. Side note: There still doesn't seem to be a correct way to express support for binding an EGLImage to a texture in OpenGL contexts. The OES extension technically only applies to GLES contexts. EGL_KHR_fence_sync used to have the same gap, but it was resolved when it was promoted to EGL 1.5. |
Okay, so this seems to take care about the side doing the modifications to the image. Not sure if all drivers implement this properly in all cases, but at least that's a interpretation of the sync object semantics that one can easily get behind and treat any missing cache flushes as driver bugs. But what about the side consuming the modified image? Does waiting for a sync object also imply that changes to resources currently bound in the waiting context are visible at that point? E.g. does a successful Also what about use-cases where the EGL images are created from resources where no EGL sync object is available to be waited on, e.g. the EGL image being constructed from a Linux dma-buf? How should changes to the underlying data be communicated to the consuming context in that case? |
Yes, use eglClientWitSync for consuming side. I've never seen cache operations with this, but it would have to be a known property of the buffer that is used to create the EGLImage. EGL will have to know that and if the buffer has any associated reference counting/wonership mechanism. dmabufs are used to create EGLImages. the EGL fence sync will work with that. |
Not sure if we are talking past each other, so just to make it clear: I'm not talking about CPU side caches, but specifically GPU caches. In the case where producer and consumer are in the same context I see that flushing the render cache before signalling the sync object created with
That will work fine when the producer is able to provide a EGL sync object. However dma-bufs may be produced/modified by APIs that aren't able to provide a EGL sync object, like V4L2 capture devices or even the wayland winsys with |
The fence is to ensure that rendering is complete and that all pixels are flushed to the buffer. If your producer is non-EGL, such as platform API, then use a platform synchronization primitive that you signal when the software or other platform rendering is complete. On the consumer side, if the platform sync is not a type that is importable to a EGLSync object, then your application, that is driving the consumer, must wait on the platform sync before proceeding with consuming/sampling the buffer. |
Right, there are other means than a EGL sync object to wait for the platform sync to be complete. However this only covers the producer side: waiting for the platform sync only ensures that the modification to the image is complete. It doesn't cover the consumer side, where the the application needs some means to tell the consuming context that the data in the EGL image might have changed and it needs to invalidate caches. Waiting for a EGL sync object might be those means when the spec language is clarified that way, but that would still not cover the case where the platform sync can't be imported into a EGL sync object, as then there is nothing to |
There is a little bit of text in the GLES and GL specifications about cache and barriers. I'll direct you there for those specifics. If EGLSync is not usable, then you will nee to use something like a semaphore between producer and consumer. Or I should say that software that drives the producer and that software that drives the consumer - application or middleware or whatever. Since its not importable to the EGL/GL driver. |
If you're not using EGLSync, presumably with a dma_fence sync via EGL_ANDROID_native_fence_sync, at least on Linux you're relying on implicit sync. That's not great IMHO, but in that case it's up to implicit sync to perform equivalent synchronization to EGLSync implicitly based on, I would assume, submission order. I wouldn't think eglClientWaitSync() is sufficient to make changes visible on the GPU. It performs a CPU-side wait and does not require a current context, so I wouldn't expect it to invalidate any GPU/GL server-side caches, as those caches may be managed relative to a context. My reading is you'd have to use eglWaitSync(). |
Oh right, Also it seems that many drivers implement |
@pdaniell-nv , I will follow up with any suggestions to make the spec text more clear for users. So this issue, which I think should be EGL, just needs to discuss any new or improved text to merge and close. |
Section 3.9.1 "lidetime and Usage of EGLImages". Need to add paragraph about timing of updates/writes such that changes are visible. |
Implicitly update shared texture resources whenever they are first used after the context has been flushed. This implements the necessary behavior to get updated content for resources shared outside of the screen without relying on any other API level trigger, discussed to be necessary in [1]. [1] KhronosGroup/OpenGL-Registry#566 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/6220 Signed-off-by: Lucas Stach <[email protected]> Reviewed-by: Christian Gmeiner <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25756>
EGL specifies that modifications to one sibling of a EGLImage are visible to all other siblings:
If an application specifies an EGLImage sibling as the destination for rendering and/or pixel download operations (e.g., as an OpenGL or OpenGL ES framebuffer object, glTexSubImage2D, etc.), the modified image results will be observed by all EGLImage siblings in all client API contexts.
However, I can't find any language on when a modification to one target must become visible
to other targets.
E.g. a texture object shared between two GL contexts that aren't in the same share group via an EGL image export/import. While we can serialize access to the resource via the known EGL synchronization primitives, we can still effectively create the situation that is solved by
glTextureBarrier
by having a target bound for rendering in one context and have another target bound for sampling in the other context. Do we need to issue a texture barrier after the rendering command in one context and another texture barrier before sampling in the other context to make sure that render/sampler caches are flushed/invalidated so the changes become visible?OES_EGL_image_external
explicitly includes language to specify that modifications to the texture object must become visible at (re-)bind time:Sampling an external texture which has been modified since it was bound will return samples which may correspond to image values either before, during, or after the modification. Binding (or re-binding if already bound) an external texture by calling BindTexture after all modifications are complete guarantees that sampling done in future draw calls will return values corresponding to the values in the buffer at or after the time that BindTexture is called.
There is no such language for non-external textures created via OES_EGL_image. So there is some ambiguity on when changes must be visible. Are
gltextureBarrier
and/orglMemoryBarrier
the right primitives to enforce visibility of modifications, or is there any other way? What about GL/GLES contexts that don't implement those primitives?The text was updated successfully, but these errors were encountered: