[client] egl: improve dmabuf import hot path performance
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled

* Removes the vector in favour of a two element array
* Removes iteration on the vector
* Create and track a per-image fence
* bind the EGLImage to the texture at creation, avoiding re-binding
* sync on GL_SYNC_FLUSH_COMMANDS_BIT and remove glFlush
This commit is contained in:
Geoffrey McRae
2025-08-31 13:48:08 +10:00
parent 2a2250b9bd
commit d5839c7efd

View File

@@ -22,7 +22,7 @@
#include "texture_buffer.h" #include "texture_buffer.h"
#include "util.h" #include "util.h"
#include "common/vector.h" #include "common/array.h"
#include "egl_dynprocs.h" #include "egl_dynprocs.h"
#include "egldebug.h" #include "egldebug.h"
@@ -30,6 +30,8 @@ struct FdImage
{ {
int fd; int fd;
EGLImage image; EGLImage image;
GLsync sync;
int texIndex;
}; };
typedef struct TexDMABUF typedef struct TexDMABUF
@@ -37,7 +39,9 @@ typedef struct TexDMABUF
TextureBuffer base; TextureBuffer base;
EGLDisplay display; EGLDisplay display;
Vector images;
struct FdImage images[2];
int lastIndex;
EGL_PixelFormat pixFmt; EGL_PixelFormat pixFmt;
unsigned fourcc; unsigned fourcc;
@@ -59,21 +63,26 @@ static void egl_texDMABUFCleanup(EGL_Texture * texture)
TextureBuffer * parent = UPCAST(TextureBuffer, texture); TextureBuffer * parent = UPCAST(TextureBuffer, texture);
TexDMABUF * this = UPCAST(TexDMABUF , parent); TexDMABUF * this = UPCAST(TexDMABUF , parent);
struct FdImage * image; for(int i = 0; i < ARRAY_LENGTH(this->images); ++i)
vector_forEachRef(image, &this->images) {
g_egl_dynProcs.eglDestroyImage(this->display, image->image); if (this->images[i].image != EGL_NO_IMAGE)
vector_clear(&this->images); {
g_egl_dynProcs.eglDestroyImage(this->display, this->images[i].image);
this->images[i].image = EGL_NO_IMAGE;
}
if (this->images[i].sync)
{
glDeleteSync(this->images[i].sync);
this->images[i].sync = 0;
}
this->images[i].fd = -1;
this->images[i].texIndex = -1;
}
egl_texUtilFreeBuffers(parent->buf, parent->texCount); egl_texUtilFreeBuffers(parent->buf, parent->texCount);
if (parent->tex[0]) if (parent->tex[0])
glDeleteTextures(parent->texCount, parent->tex); glDeleteTextures(parent->texCount, parent->tex);
if (parent->sync)
{
glDeleteSync(parent->sync);
parent->sync = 0;
}
} }
// dmabuf functions // dmabuf functions
@@ -84,17 +93,18 @@ static bool egl_texDMABUFInit(EGL_Texture ** texture, EGL_TexType type,
TexDMABUF * this = calloc(1, sizeof(*this)); TexDMABUF * this = calloc(1, sizeof(*this));
*texture = &this->base.base; *texture = &this->base.base;
if (!vector_create(&this->images, sizeof(struct FdImage), 2)) for(int i = 0; i < ARRAY_LENGTH(this->images); ++i)
{ {
free(this); this->images[i].fd = -1;
*texture = NULL; this->images[i].image = EGL_NO_IMAGE;
return false; this->images[i].sync = 0;
this->images[i].texIndex = -1;
} }
this->lastIndex = -1;
EGL_Texture * parent = &this->base.base; EGL_Texture * parent = &this->base.base;
if (!egl_texBufferStreamInit(&parent, type, display)) if (!egl_texBufferStreamInit(&parent, type, display))
{ {
vector_destroy(&this->images);
free(this); free(this);
*texture = NULL; *texture = NULL;
return false; return false;
@@ -119,8 +129,6 @@ static void egl_texDMABUFFree(EGL_Texture * texture)
TexDMABUF * this = UPCAST(TexDMABUF , parent); TexDMABUF * this = UPCAST(TexDMABUF , parent);
egl_texDMABUFCleanup(texture); egl_texDMABUFCleanup(texture);
vector_destroy(&this->images);
egl_texBufferFree(&parent->base); egl_texBufferFree(&parent->base);
free(this); free(this);
} }
@@ -198,16 +206,12 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
DEBUG_ASSERT(update->type == EGL_TEXTYPE_DMABUF); DEBUG_ASSERT(update->type == EGL_TEXTYPE_DMABUF);
EGLImage image = EGL_NO_IMAGE; struct FdImage *fdImage =
(this->images[0].fd == update->dmaFD) ? &this->images[0] :
struct FdImage * fdImage; (this->images[1].fd == update->dmaFD) ? &this->images[1] :
vector_forEachRef(fdImage, &this->images) (this->images[0].fd == -1) ? &this->images[0] :
if (fdImage->fd == update->dmaFD) &this->images[1];
{ EGLImage image = fdImage->image;
image = fdImage->image;
break;
}
if (unlikely(image == EGL_NO_IMAGE)) if (unlikely(image == EGL_NO_IMAGE))
{ {
bool setup = false; bool setup = false;
@@ -234,28 +238,26 @@ static bool egl_texDMABUFUpdate(EGL_Texture * texture,
return false; return false;
} }
if (unlikely(!vector_push(&this->images, &(struct FdImage) { fdImage->fd = update->dmaFD;
.fd = update->dmaFD, fdImage->image = image;
.image = image,
}))) int slot = (fdImage == &this->images[0]) ? 0 : 1;
fdImage->texIndex = slot;
INTERLOCKED_SECTION(parent->copyLock,
{ {
DEBUG_ERROR("Failed to store EGLImage"); glBindTexture(GL_TEXTURE_EXTERNAL_OES, parent->tex[slot]);
g_egl_dynProcs.eglDestroyImage(this->display, image); g_egl_dynProcs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
return false; });
}
} }
this->lastIndex = (fdImage == &this->images[0]) ? 0 : 1;
INTERLOCKED_SECTION(parent->copyLock, INTERLOCKED_SECTION(parent->copyLock,
{ {
glBindTexture(GL_TEXTURE_EXTERNAL_OES, parent->tex[parent->bufIndex]); if (fdImage->sync)
g_egl_dynProcs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); glDeleteSync(fdImage->sync);
fdImage->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
if (likely(parent->sync))
glDeleteSync(parent->sync);
parent->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}); });
glFlush();
return true; return true;
} }
@@ -270,23 +272,22 @@ static EGL_TexStatus egl_texDMABUFGet(EGL_Texture * texture, GLuint * tex,
TextureBuffer * parent = UPCAST(TextureBuffer, texture); TextureBuffer * parent = UPCAST(TextureBuffer, texture);
TexDMABUF * this = UPCAST(TexDMABUF , parent); TexDMABUF * this = UPCAST(TexDMABUF , parent);
if (unlikely(this->lastIndex < 0))
return EGL_TEX_STATUS_NOTREADY;
struct FdImage *cur = &this->images[this->lastIndex];
GLsync sync = 0; GLsync sync = 0;
INTERLOCKED_SECTION(parent->copyLock, INTERLOCKED_SECTION(parent->copyLock, {
{ if (cur->sync) {
if (parent->sync) sync = cur->sync;
{ cur->sync = 0;
sync = parent->sync;
parent->sync = 0;
parent->rIndex = parent->bufIndex;
if (++parent->bufIndex == parent->texCount)
parent->bufIndex = 0;
} }
}); });
if (sync) if (sync)
{ {
switch(glClientWaitSync(sync, 0, 20000000)) // 20ms switch (glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 20000000)) //20ms
{ {
case GL_ALREADY_SIGNALED: case GL_ALREADY_SIGNALED:
case GL_CONDITION_SATISFIED: case GL_CONDITION_SATISFIED:
@@ -294,10 +295,11 @@ static EGL_TexStatus egl_texDMABUFGet(EGL_Texture * texture, GLuint * tex,
break; break;
case GL_TIMEOUT_EXPIRED: case GL_TIMEOUT_EXPIRED:
// Put it back for next try
INTERLOCKED_SECTION(parent->copyLock, INTERLOCKED_SECTION(parent->copyLock,
{ {
if (!parent->sync) if (!cur->sync)
parent->sync = sync; cur->sync = sync;
else else
glDeleteSync(sync); glDeleteSync(sync);
}); });
@@ -311,7 +313,7 @@ static EGL_TexStatus egl_texDMABUFGet(EGL_Texture * texture, GLuint * tex,
} }
} }
*tex = parent->tex[parent->rIndex]; *tex = parent->tex[cur->texIndex];
if (fmt) if (fmt)
*fmt = this->pixFmt; *fmt = this->pixFmt;