[{"id":35616,"web_url":"https://patchwork.libcamera.org/comment/35616/","msgid":"<88d54676-48e2-41e6-9fb7-1ab3561382ef@collabora.com>","date":"2025-08-28T21:35:11","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"Thanks a lot for the series / all your work!\n\nI just tested it on a OnePlus6 / Freedreno - there's one issue, see below.\n\nOn 24.08.25 02:48, Bryan O'Donoghue wrote:\n> Introduce an eGL base helper class which provides an eGL context based on a\n> passed width and height.\n>\n> The initGLContext function could be overloaded to provide an interface to a\n> real display.\n>\n> A set of helper functions is provided to compile and link GLSL shaders.\n> linkShaderProgram currently compiles vertex/fragment pairs but could be\n> overloaded or passed a parameter to link a compute shader instead.\n>\n> Breaking the eGL interface away from debayering - allows to use the eGL\n> context inside of a dma-buf heap cleanly, reuse that context inside of a\n> debayer layer and conceivably reuse the context in a multi-stage shader\n> pass.\n>\n> Small note the image_attrs[] array doesn't pass checkstyle.py however the\n> elements of the array are in pairs.\n>\n> Signed-off-by: Bryan O'Donoghue<bryan.odonoghue@linaro.org>\n> ---\n>   include/libcamera/internal/egl.h | 133 +++++++++++++\n>   src/libcamera/egl.cpp            | 408 +++++++++++++++++++++++++++++++++++++++\n>   src/libcamera/meson.build        |  23 +++\n>   3 files changed, 564 insertions(+)\n>\n> diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..2c48e28e14aaa1fa8029dd18662c8ce24e6a550c\n> --- /dev/null\n> +++ b/include/libcamera/internal/egl.h\n> @@ -0,0 +1,133 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Linaro Ltd.\n> + *\n> + * Authors:\n> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>\n> + *\n> + * egl_context.cpp - Helper class for managing eGL interactions.\n> + */\n> +\n> +#pragma once\n> +\n> +#include <unistd.h>\n> +\n> +#include <libcamera/base/log.h>\n> +\n> +#include \"libcamera/internal/gbm.h\"\n> +\n> +#define EGL_EGLEXT_PROTOTYPES\n> +#include <EGL/egl.h>\n> +#include <EGL/eglext.h>\n> +#define GL_GLEXT_PROTOTYPES\n> +#include <GLES2/gl2.h>\n> +#include <GLES2/gl2ext.h>\n> +\n> +namespace libcamera {\n> +\n> +LOG_DECLARE_CATEGORY(eGL)\n> +\n> +class eGLImage\n> +{\n> +public:\n> +\teGLImage(uint32_t width, uint32_t height, uint32_t bpp, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)\n> +\t{\n> +\t\tinit(width, height, bpp, stride, texture_unit, texture_unit_uniform_id);\n> +\t}\n> +\n> +\teGLImage(uint32_t width, uint32_t height, uint32_t bpp, GLenum texture_unit, uint32_t texture_unit_uniform_id)\n> +\t{\n> +\t\tuint32_t stride = ALIGN_TO(width * bpp, 256);\n> +\n> +\t\tinit(width, height, bpp, stride, texture_unit, texture_unit_uniform_id);\n> +\t}\n> +\n> +\t~eGLImage()\n> +\t{\n> +\t\tglDeleteFramebuffers(1, &fbo_);\n> +\t\tglDeleteTextures(1, &texture_);\n> +\t}\n> +\n> +\tuint32_t width_;\n> +\tuint32_t height_;\n> +\tuint32_t stride_;\n> +\tuint32_t offset_;\n> +\tuint32_t framesize_;\n> +\tuint32_t bpp_;\n> +\tuint32_t texture_unit_uniform_id_;\n> +\tGLenum texture_unit_;\n> +\tGLuint texture_;\n> +\tGLuint fbo_;\n> +\tEGLImageKHR image_;\n> +\n> +private:\n> +\tvoid init(uint32_t width, uint32_t height, uint32_t bpp, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)\n> +\t{\n> +\t\timage_ = EGL_NO_IMAGE_KHR;\n> +\t\twidth_ = width;\n> +\t\theight_ = height;\n> +\t\tbpp_ = bpp;\n> +\t\tstride_ = stride;\n> +\t\tframesize_ = stride_ * height_;\n> +\t\ttexture_unit_ = texture_unit;\n> +\t\ttexture_unit_uniform_id_ = texture_unit_uniform_id;\n> +\n> +\t\tglGenTextures(1, &texture_);\n> +\t\tglGenFramebuffers(1, &fbo_);\n> +\t}\n> +};\n> +\n> +class eGL\n> +{\n> +public:\n> +\teGL();\n> +\t~eGL();\n> +\n> +\tint initEGLContext(GBM *gbmContext);\n> +\tvoid cleanUp();\n> +\tint createInputDMABufTexture2D(eGLImage *eglImage, int fd);\n> +\tint createOutputDMABufTexture2D(eGLImage *eglImage, int fd);\n> +\tvoid destroyDMABufTexture(eGLImage *eglImage);\n> +\tvoid createTexture2D(eGLImage *eglImage, GLint format, uint32_t width, uint32_t height, void *data);\n> +\tvoid createTexture1D(eGLImage *eglImage, GLint format, uint32_t width, void *data);\n> +\n> +\tvoid pushEnv(std::vector<std::string> &shaderEnv, const char *str);\n> +\tvoid makeCurrent();\n> +\tvoid swapBuffers();\n> +\n> +\tint compileVertexShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t\tunsigned int shaderDataLen,\n> +\t\t\t\tstd::vector<std::string> shaderEnv);\n> +\tint compileFragmentShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t\t  unsigned int shaderDataLen,\n> +\t\t\t\t  std::vector<std::string> shaderEnv);\n> +\tint linkProgram(GLuint &programIdd, GLuint fragmentshaderId, GLuint vertexshaderId);\n> +\tvoid dumpShaderSource(GLuint shaderId);\n> +\tvoid useProgram(GLuint programId);\n> +\tint syncOutput();\n> +\n> +private:\n> +\tint fd_;\n> +\n> +\tEGLDisplay display_;\n> +\tEGLContext context_;\n> +\tEGLSurface surface_;\n> +\tEGLSyncKHR sync_;\n> +\n> +\tint compileShader(int shaderType, GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t  unsigned int shaderDataLen,\n> +\t\t\t  std::vector<std::string> shaderEnv);\n> +\n> +\tint createDMABufTexture2D(eGLImage *eglImage, int fd, bool output);\n> +\n> +\tPFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;\n> +\tPFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;\n> +\n> +\tPFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;\n> +\tPFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;\n> +\n> +\tPFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;\n> +\tPFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;\n> +\tPFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR;\n> +};\n> +} //namespace libcamera\n> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..b56c65a33837bb31a3e19613f4abb52d77880301\n> --- /dev/null\n> +++ b/src/libcamera/egl.cpp\n> @@ -0,0 +1,408 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Linaro Ltd.\n> + *\n> + * Authors:\n> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>\n> + *\n> + * egl.cpp - Helper class for managing eGL interactions.\n> + */\n> +\n> +#include \"libcamera/internal/egl.h\"\n> +\n> +#include <fcntl.h>\n> +#include <sys/ioctl.h>\n> +#include <sys/mman.h>\n> +#include <unistd.h>\n> +\n> +#include <libdrm/drm_fourcc.h>\n> +#include <linux/dma-buf.h>\n> +#include <linux/dma-heap.h>\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(eGL)\n> +\n> +eGL::eGL()\n> +{\n> +}\n> +\n> +eGL::~eGL()\n> +{\n> +}\n> +\n> +int eGL::syncOutput(void)\n> +{\n> +\tglFlush();\n> +\teglClientWaitSyncKHR(display_, sync_, 0, EGL_FOREVER_KHR);\n> +\n> +\treturn 0;\n> +}\n> +\n> +// Create linear image attached to previous BO object\n> +int eGL::createDMABufTexture2D(eGLImage *eglImage, int fd, bool output)\n> +{\n> +\tint ret = 0;\n> +\n> +\tEGLint image_attrs[] = {\n> +\t\tEGL_WIDTH, (EGLint)eglImage->width_,\n> +\t\tEGL_HEIGHT, (EGLint)eglImage->height_,\n> +\t\tEGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,\n> +\t\tEGL_DMA_BUF_PLANE0_FD_EXT, fd,\n> +\t\tEGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,\n> +\t\tEGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)eglImage->stride_,\n> +\t\tEGL_NONE, EGL_NONE,\t/* modifier lo */\n> +\t\tEGL_NONE, EGL_NONE,\t/* modifier hi */\n\nThese two cause eglCreateImageKHR() to fail on this platform. Simply \nreplacing it with\n\n         EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, 0,\n         EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, 0,\n\ndoes the trick, though.\n\n> +\t\tEGL_NONE,\n> +\t};\n> +\n> +\teglImage->image_ = eglCreateImageKHR(display_, EGL_NO_CONTEXT,\n> +\t\t\t\t\t     EGL_LINUX_DMA_BUF_EXT,\n> +\t\t\t\t\t     NULL, image_attrs);\n> +\n> +\tif (eglImage->image_ == EGL_NO_IMAGE_KHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateImageKHR fail\";\n> +\t\tret = -ENODEV;\n> +\t\tgoto done;\n> +\t}\n> +\n> +\t// Bind texture unit and texture\n> +\tglActiveTexture(eglImage->texture_unit_);\n> +\tglBindTexture(GL_TEXTURE_2D, eglImage->texture_);\n> +\n> +\t// Generate texture with filter semantics\n> +\tglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage->image_);\n> +\n> +\t// Nearest filtering\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n> +\n> +\t// Wrap to edge to avoid edge artifacts\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n> +\n> +\tif (output) {\n> +\t\t// Generate a framebuffer from our texture direct to dma-buf handle buffer\n> +\t\tglBindFramebuffer(GL_FRAMEBUFFER, eglImage->fbo_);\n> +\t\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, eglImage->texture_, 0);\n> +\n> +\t\tGLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);\n> +\t\tif (err!= GL_FRAMEBUFFER_COMPLETE) {\n> +\t\t\tLOG(eGL, Error) << \"glFrameBufferTexture2D error \" << err;\n> +\t\t\tret = -ENODEV;\n> +\t\t\tgoto done;\n> +\t\t}\n> +\t}\n> +done:\n> +\treturn ret;\n> +}\n> +\n> +int eGL::createInputDMABufTexture2D(eGLImage *eglImage, int fd)\n> +{\n> +\treturn createDMABufTexture2D(eglImage, fd, false);\n> +}\n> +int eGL::createOutputDMABufTexture2D(eGLImage *eglImage, int fd)\n> +{\n> +\treturn createDMABufTexture2D(eglImage, fd, true);\n> +}\n> +\n> +void eGL::destroyDMABufTexture(eGLImage *eglImage)\n> +{\n> +\teglDestroyImage(display_, eglImage->image_);\n> +}\n> +\n> +// Generate a 2D texture from an input buffer directly\n> +void eGL::createTexture2D(eGLImage *eglImage, GLint format, uint32_t width, uint32_t height, void *data)\n> +{\n> +\tglActiveTexture(eglImage->texture_unit_);\n> +\tglBindTexture(GL_TEXTURE_2D, eglImage->texture_);\n> +\n> +\t// Generate texture, bind, associate image to texture, configure, unbind\n> +\tglTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);\n> +\n> +\t// Nearest filtering\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n> +\n> +\t// Wrap to edge to avoid edge artifacts\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n> +}\n> +\n> +int eGL::initEGLContext(GBM *gbmContext)\n> +{\n> +\tEGLint configAttribs[] = {\n> +\t\tEGL_RED_SIZE, 8,\n> +\t\tEGL_GREEN_SIZE, 8,\n> +\t\tEGL_BLUE_SIZE, 8,\n> +\t\tEGL_ALPHA_SIZE, 8,\n> +\t\tEGL_SURFACE_TYPE, EGL_WINDOW_BIT,\n> +\t\tEGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,\n> +\t\tEGL_NONE\n> +\t};\n> +\n> +\tEGLint contextAttribs[] = {\n> +\t\tEGL_CONTEXT_MAJOR_VERSION, 2,\n> +\t\tEGL_NONE\n> +\t};\n> +\n> +\tEGLint numConfigs;\n> +\tEGLConfig config;\n> +\tEGLint major;\n> +\tEGLint minor;\n> +\n> +\tif (!eglBindAPI(EGL_OPENGL_ES_API)) {\n> +\t\tLOG(eGL, Error) << \"API bind fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tdisplay_ = eglGetDisplay(gbmContext->getDevice());\n> +\tif (display_ == EGL_NO_DISPLAY) {\n> +\t\tLOG(eGL, Error) << \"Unable to get EGL display\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tif (eglInitialize(display_, &major, &minor) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglInitialize fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tLOG(eGL, Info) << \"EGL: version \" << major << \".\" << minor;\n> +\tLOG(eGL, Info) << \"EGL: EGL_VERSION: \" << eglQueryString(display_, EGL_VERSION);\n> +\tLOG(eGL, Info) << \"EGL: EGL_VENDOR: \" << eglQueryString(display_, EGL_VENDOR);\n> +\tLOG(eGL, Info) << \"EGL: EGL_CLIENT_APIS: \" << eglQueryString(display_, EGL_CLIENT_APIS);\n> +\tLOG(eGL, Info) << \"EGL: EGL_EXTENSIONS: \" << eglQueryString(display_, EGL_EXTENSIONS);\n> +\n> +\teglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress(\"eglCreateImageKHR\");\n> +\tif (!eglCreateImageKHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateImageKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress(\"eglDestroyImageKHR\");\n> +\tif (!eglDestroyImageKHR) {\n> +\t\tLOG(eGL, Error) << \"eglDestroyImageKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress(\"glEGLImageTargetTexture2DOES\");\n> +\tif (!glEGLImageTargetTexture2DOES) {\n> +\t\tLOG(eGL, Error) << \"glEGLImageTargetTexture2DOES not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)eglGetProcAddress(\"eglCreateSyncKHR\");\n> +\tif (!eglCreateSyncKHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateSyncKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)eglGetProcAddress(\"eglDestroySyncKHR\");\n> +\tif (!eglDestroySyncKHR) {\n> +\t\tLOG(eGL, Error) << \"eglDestroySyncKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)eglGetProcAddress(\"eglClientWaitSyncKHR\");\n> +\tif (!eglClientWaitSyncKHR) {\n> +\t\tLOG(eGL, Error) << \"eglClientWaitSyncKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tif (eglChooseConfig(display_, configAttribs, &config, 1, &numConfigs) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglChooseConfig fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tcontext_ = eglCreateContext(display_, config, EGL_NO_CONTEXT, contextAttribs);\n> +\tif (context_ == EGL_NO_CONTEXT) {\n> +\t\tLOG(eGL, Error) << \"eglContext returned EGL_NO_CONTEXT\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tmakeCurrent();\n> +\n> +\tsync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL);\n> +\tif (sync_ == EGL_NO_SYNC_KHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateSyncKHR fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\treturn 0;\n> +fail:\n> +\n> +\treturn -ENODEV;\n> +}\n> +\n> +void eGL::cleanUp(void)\n> +{\n> +\tif (sync_) {\n> +\t\tmakeCurrent();\n> +\t\teglDestroySyncKHR(display_, sync_);\n> +\t}\n> +\n> +}\n> +void eGL::makeCurrent(void)\n> +{\n> +\tif (eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglMakeCurrent fail\";\n> +\t}\n> +}\n> +\n> +void eGL::swapBuffers(void)\n> +{\n> +\tif (eglSwapBuffers(display_, surface_) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglSwapBuffers fail\";\n> +\t}\n> +}\n> +\n> +void eGL::useProgram(GLuint programId)\n> +{\n> +\tglUseProgram(programId);\n> +}\n> +\n> +void eGL::pushEnv(std::vector<std::string> &shaderEnv, const char *str)\n> +{\n> +\tstd::string addStr = str;\n> +\n> +\taddStr.push_back('\\n');\n> +\tshaderEnv.push_back(addStr);\n> +}\n> +\n> +int eGL::compileVertexShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t     unsigned int shaderDataLen,\n> +\t\t\t     std::vector<std::string> shaderEnv)\n> +{\n> +\treturn compileShader(GL_VERTEX_SHADER, shaderId, shaderData, shaderDataLen, shaderEnv);\n> +}\n> +\n> +int eGL::compileFragmentShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t       unsigned int shaderDataLen,\n> +\t\t\t       std::vector<std::string> shaderEnv)\n> +{\n> +\treturn compileShader(GL_FRAGMENT_SHADER, shaderId, shaderData, shaderDataLen, shaderEnv);\n> +}\n> +\n> +int eGL::compileShader(int shaderType, GLuint &shaderId, unsigned char *shaderData,\n> +\t\t       unsigned int shaderDataLen,\n> +\t\t       std::vector<std::string> shaderEnv)\n> +{\n> +\tGLchar **shaderSourceData;\n> +\tGLint *shaderDataLengths;\n> +\tGLint success;\n> +\tGLsizei count;\n> +\tsize_t i;\n> +\n> +\tcount = 1 + shaderEnv.size();\n> +\tshaderSourceData = new GLchar *[count];\n> +\tshaderDataLengths = new GLint[count];\n> +\n> +\t// Prefix defines before main body of shader\n> +\tfor (i = 0; i < shaderEnv.size(); i++) {\n> +\t\tshaderSourceData[i] = (GLchar *)shaderEnv[i].c_str();\n> +\t\tshaderDataLengths[i] = shaderEnv[i].length();\n> +\t}\n> +\n> +\t// Now the main body of the shader program\n> +\tshaderSourceData[i] = (GLchar *)shaderData;\n> +\tshaderDataLengths[i] = shaderDataLen;\n> +\n> +\t// And create the shader\n> +\tshaderId = glCreateShader(shaderType);\n> +\tglShaderSource(shaderId, count, shaderSourceData, shaderDataLengths);\n> +\tglCompileShader(shaderId);\n> +\n> +\t// Check status\n> +\tglGetShaderiv(shaderId, GL_COMPILE_STATUS, &success);\n> +\tif (success == GL_FALSE) {\n> +\t\tGLint sizeLog = 0;\n> +\t\tGLchar *infoLog;\n> +\n> +\t\tglGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &sizeLog);\n> +\t\tinfoLog = new GLchar[sizeLog];\n> +\n> +\t\tglGetShaderInfoLog(shaderId, sizeLog, &sizeLog, infoLog);\n> +\t\tLOG(eGL, Error) << infoLog;\n> +\n> +\t\tdelete[] infoLog;\n> +\t}\n> +\n> +\tdelete[] shaderSourceData;\n> +\tdelete[] shaderDataLengths;\n> +\n> +\treturn !(success == GL_TRUE);\n> +}\n> +\n> +void eGL::dumpShaderSource(GLuint shaderId)\n> +{\n> +\tGLint shaderLength = 0;\n> +\tGLchar *shaderSource;\n> +\n> +\tglGetShaderiv(shaderId, GL_SHADER_SOURCE_LENGTH, &shaderLength);\n> +\n> +\tLOG(eGL, Debug) << \"Shader length is \" << shaderLength;\n> +\n> +\tif (shaderLength > 0) {\n> +\t\tshaderSource = new GLchar[shaderLength];\n> +\t\tif (!shaderSource)\n> +\t\t\treturn;\n> +\n> +\t\tglGetShaderSource(shaderId, shaderLength, &shaderLength, shaderSource);\n> +\t\tif (shaderLength) {\n> +\t\t\tLOG(eGL, Debug) << \"Shader source = \" << shaderSource;\n> +\t\t}\n> +\t\tdelete[] shaderSource;\n> +\t}\n> +}\n> +\n> +int eGL::linkProgram(GLuint &programId, GLuint vertexshaderId, GLuint fragmentshaderId)\n> +{\n> +\tGLint success;\n> +\tGLenum err;\n> +\n> +\tprogramId = glCreateProgram();\n> +\tif (!programId)\n> +\t\tgoto fail;\n> +\n> +\tglAttachShader(programId, vertexshaderId);\n> +\tif ((err = glGetError()) != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Attach compute vertex shader fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglAttachShader(programId, fragmentshaderId);\n> +\tif ((err = glGetError()) != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Attach compute vertex shader fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglLinkProgram(programId);\n> +\tif ((err = glGetError()) != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Link program fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglDetachShader(programId, fragmentshaderId);\n> +\tglDetachShader(programId, vertexshaderId);\n> +\n> +\t// Check status\n> +\tglGetProgramiv(programId, GL_LINK_STATUS, &success);\n> +\tif (success == GL_FALSE) {\n> +\t\tGLint sizeLog = 0;\n> +\t\tGLchar *infoLog;\n> +\n> +\t\tglGetProgramiv(programId, GL_INFO_LOG_LENGTH, &sizeLog);\n> +\t\tinfoLog = new GLchar[sizeLog];\n> +\n> +\t\tglGetProgramInfoLog(programId, sizeLog, &sizeLog, infoLog);\n> +\t\tLOG(eGL, Error) << infoLog;\n> +\n> +\t\tdelete[] infoLog;\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\treturn 0;\n> +fail:\n> +\treturn -ENODEV;\n> +}\n> +} // namespace libcamera\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 64270b571cea2ece8d4dfea8a23b8edf60de70d3..705c328a27f68377573916a77573335f4f4ab3cc 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -78,6 +78,27 @@ if libgbm.found() and gbm_works\n>       ])\n>   endif\n>   \n> +libegl = cc.find_library('EGL', required : false)\n> +libglesv2 = cc.find_library('GLESv2', required : false)\n> +mesa_works = cc.check_header('EGL/egl.h', required: false)\n> +\n> +if libegl.found() and mesa_works\n> +    config_h.set('HAVE_LIBEGL', 1)\n> +endif\n> +\n> +if libglesv2.found() and mesa_works\n> +    config_h.set('HAVE_GLESV2', 1)\n> +endif\n> +\n> +if mesa_works and gbm_works\n> +    libcamera_internal_sources += files([\n> +        'egl.cpp',\n> +    ])\n> +    gles_headless_enabled = true\n> +else\n> +    gles_headless_enabled = false\n> +endif\n> +\n>   subdir('base')\n>   subdir('converter')\n>   subdir('ipa')\n> @@ -191,7 +212,9 @@ libcamera_deps += [\n>       libcamera_base_private,\n>       libcrypto,\n>       libdl,\n> +    libegl,\n>       libgbm,\n> +    libglesv2,\n>       liblttng,\n>       libudev,\n>       libyaml,\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 47F2FBD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 28 Aug 2025 21:35:24 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DA09E69301;\n\tThu, 28 Aug 2025 23:35:22 +0200 (CEST)","from sender4-op-o12.zoho.com (sender4-op-o12.zoho.com\n\t[136.143.188.12])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id ADF94692E3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Aug 2025 23:35:20 +0200 (CEST)","by mx.zohomail.com with SMTPS id 1756416914764552.5223261909331;\n\tThu, 28 Aug 2025 14:35:14 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"NLCJOSJ6\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1756416916; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=X4JqXZJpMcpfAKTzj0vcgeNrjuaeg5wEaDoFWzbLwYc4U57Ysr8CZEHsvWHJPoRAfpTj8+VybsxqNu9+cYHj4vWTeBC8CiJGOFnFn/fbCij9R1Jiyj9ONGpv2BbOoIIw95OpMH3/kbg47NWEIPtBaBgI/sLmUpKMrW2CKmXHaXY=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1756416916;\n\th=Content-Type:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To:Cc;\n\tbh=tI6f7o8Un9Ps9OtK93+0J0l/qI12NQeMjQYb658AGvA=; \n\tb=jfrd6uLCpdti7gj07r7JuUODb2L4xWPpAyg0gACRaVx8i2SgHe8E+fXqGEBFhEMVU7vvrNxWP81ygwT4eHQS+2jtWFoQm+IfqKxXTjfYWzT4jQz6gG98etayQS80epTLrLXi2vLDmEogYTIVm7m7hbY9nRX1/8fFOcrU1ZRYvcE=","ARC-Authentication-Results":"i=1; mx.zohomail.com;\n\tdkim=pass  header.i=collabora.com;\n\tspf=pass  smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1756416916;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Content-Type:Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:References:From:From:In-Reply-To:Message-Id:Reply-To:Cc;\n\tbh=tI6f7o8Un9Ps9OtK93+0J0l/qI12NQeMjQYb658AGvA=;\n\tb=NLCJOSJ6+Ik4Qs5eZbShn46uFV9EdBsACG6OYWINa/fMDV6ECV30Wd4uQeaVLujf\n\txeHJ+qIh2iMSv9MPdmvCgUY5wah2p1sa7YlInOUsvHw/DKG/g4h7dyWscjRniEuzijS\n\tiywt//SzauargqjIb27NPecLMmIFrFhSt5l4w/7I=","Content-Type":"multipart/alternative;\n\tboundary=\"------------GZzVPXRAWTuxGPx67Ec4tawj\"","Message-ID":"<88d54676-48e2-41e6-9fb7-1ab3561382ef@collabora.com>","Date":"Thu, 28 Aug 2025 23:35:11 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"libcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>","Content-Language":"en-US, de-DE","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35645,"web_url":"https://patchwork.libcamera.org/comment/35645/","msgid":"<2e3f64d5-982f-4c5f-9443-5db915a37dff@collabora.com>","date":"2025-08-31T13:58:55","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"On 24.08.25 02:48, Bryan O'Donoghue wrote:\n> Introduce an eGL base helper class which provides an eGL context based on a\n> passed width and height.\n>\n> The initGLContext function could be overloaded to provide an interface to a\n> real display.\n>\n> A set of helper functions is provided to compile and link GLSL shaders.\n> linkShaderProgram currently compiles vertex/fragment pairs but could be\n> overloaded or passed a parameter to link a compute shader instead.\n>\n> Breaking the eGL interface away from debayering - allows to use the eGL\n> context inside of a dma-buf heap cleanly, reuse that context inside of a\n> debayer layer and conceivably reuse the context in a multi-stage shader\n> pass.\n>\n> Small note the image_attrs[] array doesn't pass checkstyle.py however the\n> elements of the array are in pairs.\n>\n> Signed-off-by: Bryan O'Donoghue<bryan.odonoghue@linaro.org>\n> ---\n>   include/libcamera/internal/egl.h | 133 +++++++++++++\n>   src/libcamera/egl.cpp            | 408 +++++++++++++++++++++++++++++++++++++++\n>   src/libcamera/meson.build        |  23 +++\n>   3 files changed, 564 insertions(+)\n>\n> diff --git a/include/libcamera/internal/egl.h b/include/libcamera/internal/egl.h\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..2c48e28e14aaa1fa8029dd18662c8ce24e6a550c\n> --- /dev/null\n> +++ b/include/libcamera/internal/egl.h\n> @@ -0,0 +1,133 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Linaro Ltd.\n> + *\n> + * Authors:\n> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>\n> + *\n> + * egl_context.cpp - Helper class for managing eGL interactions.\n> + */\n> +\n> +#pragma once\n> +\n> +#include <unistd.h>\n> +\n> +#include <libcamera/base/log.h>\n> +\n> +#include \"libcamera/internal/gbm.h\"\n> +\n> +#define EGL_EGLEXT_PROTOTYPES\n> +#include <EGL/egl.h>\n> +#include <EGL/eglext.h>\n> +#define GL_GLEXT_PROTOTYPES\n> +#include <GLES2/gl2.h>\n> +#include <GLES2/gl2ext.h>\n> +\n> +namespace libcamera {\n> +\n> +LOG_DECLARE_CATEGORY(eGL)\n> +\n> +class eGLImage\n> +{\n> +public:\n> +\teGLImage(uint32_t width, uint32_t height, uint32_t bpp, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)\n> +\t{\n> +\t\tinit(width, height, bpp, stride, texture_unit, texture_unit_uniform_id);\n> +\t}\n> +\n> +\teGLImage(uint32_t width, uint32_t height, uint32_t bpp, GLenum texture_unit, uint32_t texture_unit_uniform_id)\n> +\t{\n> +\t\tuint32_t stride = ALIGN_TO(width * bpp, 256);\n> +\n> +\t\tinit(width, height, bpp, stride, texture_unit, texture_unit_uniform_id);\n> +\t}\n> +\n> +\t~eGLImage()\n> +\t{\n> +\t\tglDeleteFramebuffers(1, &fbo_);\n> +\t\tglDeleteTextures(1, &texture_);\n> +\t}\n> +\n> +\tuint32_t width_;\n> +\tuint32_t height_;\n> +\tuint32_t stride_;\n> +\tuint32_t offset_;\n> +\tuint32_t framesize_;\n> +\tuint32_t bpp_;\n> +\tuint32_t texture_unit_uniform_id_;\n> +\tGLenum texture_unit_;\n> +\tGLuint texture_;\n> +\tGLuint fbo_;\n> +\tEGLImageKHR image_;\n> +\n> +private:\n> +\tvoid init(uint32_t width, uint32_t height, uint32_t bpp, uint32_t stride, GLenum texture_unit, uint32_t texture_unit_uniform_id)\n> +\t{\n> +\t\timage_ = EGL_NO_IMAGE_KHR;\n> +\t\twidth_ = width;\n> +\t\theight_ = height;\n> +\t\tbpp_ = bpp;\n> +\t\tstride_ = stride;\n> +\t\tframesize_ = stride_ * height_;\n> +\t\ttexture_unit_ = texture_unit;\n> +\t\ttexture_unit_uniform_id_ = texture_unit_uniform_id;\n> +\n> +\t\tglGenTextures(1, &texture_);\n> +\t\tglGenFramebuffers(1, &fbo_);\n> +\t}\n> +};\n> +\n> +class eGL\n> +{\n> +public:\n> +\teGL();\n> +\t~eGL();\n> +\n> +\tint initEGLContext(GBM *gbmContext);\n> +\tvoid cleanUp();\n> +\tint createInputDMABufTexture2D(eGLImage *eglImage, int fd);\n> +\tint createOutputDMABufTexture2D(eGLImage *eglImage, int fd);\n> +\tvoid destroyDMABufTexture(eGLImage *eglImage);\n> +\tvoid createTexture2D(eGLImage *eglImage, GLint format, uint32_t width, uint32_t height, void *data);\n> +\tvoid createTexture1D(eGLImage *eglImage, GLint format, uint32_t width, void *data);\n> +\n> +\tvoid pushEnv(std::vector<std::string> &shaderEnv, const char *str);\n> +\tvoid makeCurrent();\n> +\tvoid swapBuffers();\n> +\n> +\tint compileVertexShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t\tunsigned int shaderDataLen,\n> +\t\t\t\tstd::vector<std::string> shaderEnv);\n> +\tint compileFragmentShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t\t  unsigned int shaderDataLen,\n> +\t\t\t\t  std::vector<std::string> shaderEnv);\n> +\tint linkProgram(GLuint &programIdd, GLuint fragmentshaderId, GLuint vertexshaderId);\n> +\tvoid dumpShaderSource(GLuint shaderId);\n> +\tvoid useProgram(GLuint programId);\n> +\tint syncOutput();\n> +\n> +private:\n> +\tint fd_;\n> +\n> +\tEGLDisplay display_;\n> +\tEGLContext context_;\n> +\tEGLSurface surface_;\n> +\tEGLSyncKHR sync_;\n> +\n> +\tint compileShader(int shaderType, GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t  unsigned int shaderDataLen,\n> +\t\t\t  std::vector<std::string> shaderEnv);\n> +\n> +\tint createDMABufTexture2D(eGLImage *eglImage, int fd, bool output);\n> +\n> +\tPFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;\n> +\tPFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;\n> +\n> +\tPFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;\n> +\tPFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;\n> +\n> +\tPFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;\n> +\tPFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;\n> +\tPFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR;\n> +};\n> +} //namespace libcamera\n> diff --git a/src/libcamera/egl.cpp b/src/libcamera/egl.cpp\n> new file mode 100644\n> index 0000000000000000000000000000000000000000..b56c65a33837bb31a3e19613f4abb52d77880301\n> --- /dev/null\n> +++ b/src/libcamera/egl.cpp\n> @@ -0,0 +1,408 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024, Linaro Ltd.\n> + *\n> + * Authors:\n> + * Bryan O'Donoghue<bryan.odonoghue@linaro.org>\n> + *\n> + * egl.cpp - Helper class for managing eGL interactions.\n> + */\n> +\n> +#include \"libcamera/internal/egl.h\"\n> +\n> +#include <fcntl.h>\n> +#include <sys/ioctl.h>\n> +#include <sys/mman.h>\n> +#include <unistd.h>\n> +\n> +#include <libdrm/drm_fourcc.h>\n> +#include <linux/dma-buf.h>\n> +#include <linux/dma-heap.h>\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(eGL)\n> +\n> +eGL::eGL()\n> +{\n> +}\n> +\n> +eGL::~eGL()\n> +{\n> +}\n> +\n> +int eGL::syncOutput(void)\n> +{\n> +\tglFlush();\n> +\teglClientWaitSyncKHR(display_, sync_, 0, EGL_FOREVER_KHR);\n\nI think there are several issue here:\n\n 1. eglClientWaitSyncKHR() with a 0 flag - i.e. no wait condition - is a\n    no-op.\n 2. The only supported flag in Mesa is EGL_SYNC_FLUSH_COMMANDS_BIT_KHR\n    and all it does is triggering a flush if needed - i.e. it should be\n    equivalent to the glFlush() above if I'm not mistaken.\n    (https://gitlab.freedesktop.org/mesa/mesa/-/blob/9a03aee7035e7f474ac33edc92954d45e68670e4/src/egl/drivers/dri2/egl_dri2.c#L2932-2963)\n 3. Flushing alone does not guarantee that the work has actually\n    completed, but only that the commands have been send to the GPU.\n    That means the output buffer might still not be ready for\n    consumption after this command. This is no problem in cases where\n    the buffer gets imported into GL/VK/V4L2 etc. by the client -\n    assuming a driver with implicit sync support - but can be an issue\n    if the buffer is used by a client without implicit sync support -\n    most importantly when reading from CPU / mmapping. Note that\n    DMA_BUF_IOCTL_SYNC (which a client is expected to use in this case)\n    explicitly does *not* cover implicit sync, see the quote below. If\n    I'm not mistaken the only clean solution here - without essentially\n    breaking API and requiring consumers to support implicit sync - is\n    to explicitly wait for the buffer-write to be complete before\n    handing over to the client. And the best option I see for that is\n    dma_buf_export_sync_file\n    <https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file>\n\n 4. If we introduce such waiting, it'll probably make sense to ensure\n    that work on the next buffer can already begin - i.e. we'd want\n    things to become more async.\n\nRegards,\n\nRobert\n\n> The synchronization provided via DMA_BUF_IOCTL_SYNC only provides \n> cache coherency. It does not prevent other processes or devices from \n> accessing the memory at the same time. If synchronization with a GPU \n> or other device driver is required, it is the client’s responsibility \n> to wait for buffer to be ready for reading or writing before calling \n> this ioctl with DMA_BUF_SYNC_START.\nfrom \nhttps://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_sync\n\n> +\n> +\treturn 0;\n> +}\n> +\n> +// Create linear image attached to previous BO object\n> +int eGL::createDMABufTexture2D(eGLImage *eglImage, int fd, bool output)\n> +{\n> +\tint ret = 0;\n> +\n> +\tEGLint image_attrs[] = {\n> +\t\tEGL_WIDTH, (EGLint)eglImage->width_,\n> +\t\tEGL_HEIGHT, (EGLint)eglImage->height_,\n> +\t\tEGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,\n> +\t\tEGL_DMA_BUF_PLANE0_FD_EXT, fd,\n> +\t\tEGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,\n> +\t\tEGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)eglImage->stride_,\n> +\t\tEGL_NONE, EGL_NONE,\t/* modifier lo */\n> +\t\tEGL_NONE, EGL_NONE,\t/* modifier hi */\n> +\t\tEGL_NONE,\n> +\t};\n> +\n> +\teglImage->image_ = eglCreateImageKHR(display_, EGL_NO_CONTEXT,\n> +\t\t\t\t\t     EGL_LINUX_DMA_BUF_EXT,\n> +\t\t\t\t\t     NULL, image_attrs);\n> +\n> +\tif (eglImage->image_ == EGL_NO_IMAGE_KHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateImageKHR fail\";\n> +\t\tret = -ENODEV;\n> +\t\tgoto done;\n> +\t}\n> +\n> +\t// Bind texture unit and texture\n> +\tglActiveTexture(eglImage->texture_unit_);\n> +\tglBindTexture(GL_TEXTURE_2D, eglImage->texture_);\n> +\n> +\t// Generate texture with filter semantics\n> +\tglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage->image_);\n> +\n> +\t// Nearest filtering\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n> +\n> +\t// Wrap to edge to avoid edge artifacts\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n> +\n> +\tif (output) {\n> +\t\t// Generate a framebuffer from our texture direct to dma-buf handle buffer\n> +\t\tglBindFramebuffer(GL_FRAMEBUFFER, eglImage->fbo_);\n> +\t\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, eglImage->texture_, 0);\n> +\n> +\t\tGLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);\n> +\t\tif (err!= GL_FRAMEBUFFER_COMPLETE) {\n> +\t\t\tLOG(eGL, Error) << \"glFrameBufferTexture2D error \" << err;\n> +\t\t\tret = -ENODEV;\n> +\t\t\tgoto done;\n> +\t\t}\n> +\t}\n> +done:\n> +\treturn ret;\n> +}\n> +\n> +int eGL::createInputDMABufTexture2D(eGLImage *eglImage, int fd)\n> +{\n> +\treturn createDMABufTexture2D(eglImage, fd, false);\n> +}\n> +int eGL::createOutputDMABufTexture2D(eGLImage *eglImage, int fd)\n> +{\n> +\treturn createDMABufTexture2D(eglImage, fd, true);\n> +}\n> +\n> +void eGL::destroyDMABufTexture(eGLImage *eglImage)\n> +{\n> +\teglDestroyImage(display_, eglImage->image_);\n> +}\n> +\n> +// Generate a 2D texture from an input buffer directly\n> +void eGL::createTexture2D(eGLImage *eglImage, GLint format, uint32_t width, uint32_t height, void *data)\n> +{\n> +\tglActiveTexture(eglImage->texture_unit_);\n> +\tglBindTexture(GL_TEXTURE_2D, eglImage->texture_);\n> +\n> +\t// Generate texture, bind, associate image to texture, configure, unbind\n> +\tglTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);\n> +\n> +\t// Nearest filtering\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n> +\n> +\t// Wrap to edge to avoid edge artifacts\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n> +\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n> +}\n> +\n> +int eGL::initEGLContext(GBM *gbmContext)\n> +{\n> +\tEGLint configAttribs[] = {\n> +\t\tEGL_RED_SIZE, 8,\n> +\t\tEGL_GREEN_SIZE, 8,\n> +\t\tEGL_BLUE_SIZE, 8,\n> +\t\tEGL_ALPHA_SIZE, 8,\n> +\t\tEGL_SURFACE_TYPE, EGL_WINDOW_BIT,\n> +\t\tEGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,\n> +\t\tEGL_NONE\n> +\t};\n> +\n> +\tEGLint contextAttribs[] = {\n> +\t\tEGL_CONTEXT_MAJOR_VERSION, 2,\n> +\t\tEGL_NONE\n> +\t};\n> +\n> +\tEGLint numConfigs;\n> +\tEGLConfig config;\n> +\tEGLint major;\n> +\tEGLint minor;\n> +\n> +\tif (!eglBindAPI(EGL_OPENGL_ES_API)) {\n> +\t\tLOG(eGL, Error) << \"API bind fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tdisplay_ = eglGetDisplay(gbmContext->getDevice());\n> +\tif (display_ == EGL_NO_DISPLAY) {\n> +\t\tLOG(eGL, Error) << \"Unable to get EGL display\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tif (eglInitialize(display_, &major, &minor) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglInitialize fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tLOG(eGL, Info) << \"EGL: version \" << major << \".\" << minor;\n> +\tLOG(eGL, Info) << \"EGL: EGL_VERSION: \" << eglQueryString(display_, EGL_VERSION);\n> +\tLOG(eGL, Info) << \"EGL: EGL_VENDOR: \" << eglQueryString(display_, EGL_VENDOR);\n> +\tLOG(eGL, Info) << \"EGL: EGL_CLIENT_APIS: \" << eglQueryString(display_, EGL_CLIENT_APIS);\n> +\tLOG(eGL, Info) << \"EGL: EGL_EXTENSIONS: \" << eglQueryString(display_, EGL_EXTENSIONS);\n> +\n> +\teglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress(\"eglCreateImageKHR\");\n> +\tif (!eglCreateImageKHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateImageKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress(\"eglDestroyImageKHR\");\n> +\tif (!eglDestroyImageKHR) {\n> +\t\tLOG(eGL, Error) << \"eglDestroyImageKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress(\"glEGLImageTargetTexture2DOES\");\n> +\tif (!glEGLImageTargetTexture2DOES) {\n> +\t\tLOG(eGL, Error) << \"glEGLImageTargetTexture2DOES not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)eglGetProcAddress(\"eglCreateSyncKHR\");\n> +\tif (!eglCreateSyncKHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateSyncKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)eglGetProcAddress(\"eglDestroySyncKHR\");\n> +\tif (!eglDestroySyncKHR) {\n> +\t\tLOG(eGL, Error) << \"eglDestroySyncKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\teglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)eglGetProcAddress(\"eglClientWaitSyncKHR\");\n> +\tif (!eglClientWaitSyncKHR) {\n> +\t\tLOG(eGL, Error) << \"eglClientWaitSyncKHR not found\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tif (eglChooseConfig(display_, configAttribs, &config, 1, &numConfigs) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglChooseConfig fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tcontext_ = eglCreateContext(display_, config, EGL_NO_CONTEXT, contextAttribs);\n> +\tif (context_ == EGL_NO_CONTEXT) {\n> +\t\tLOG(eGL, Error) << \"eglContext returned EGL_NO_CONTEXT\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tmakeCurrent();\n> +\n> +\tsync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL);\n> +\tif (sync_ == EGL_NO_SYNC_KHR) {\n> +\t\tLOG(eGL, Error) << \"eglCreateSyncKHR fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\treturn 0;\n> +fail:\n> +\n> +\treturn -ENODEV;\n> +}\n> +\n> +void eGL::cleanUp(void)\n> +{\n> +\tif (sync_) {\n> +\t\tmakeCurrent();\n> +\t\teglDestroySyncKHR(display_, sync_);\n> +\t}\n> +\n> +}\n> +void eGL::makeCurrent(void)\n> +{\n> +\tif (eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, context_) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglMakeCurrent fail\";\n> +\t}\n> +}\n> +\n> +void eGL::swapBuffers(void)\n> +{\n> +\tif (eglSwapBuffers(display_, surface_) != EGL_TRUE) {\n> +\t\tLOG(eGL, Error) << \"eglSwapBuffers fail\";\n> +\t}\n> +}\n> +\n> +void eGL::useProgram(GLuint programId)\n> +{\n> +\tglUseProgram(programId);\n> +}\n> +\n> +void eGL::pushEnv(std::vector<std::string> &shaderEnv, const char *str)\n> +{\n> +\tstd::string addStr = str;\n> +\n> +\taddStr.push_back('\\n');\n> +\tshaderEnv.push_back(addStr);\n> +}\n> +\n> +int eGL::compileVertexShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t     unsigned int shaderDataLen,\n> +\t\t\t     std::vector<std::string> shaderEnv)\n> +{\n> +\treturn compileShader(GL_VERTEX_SHADER, shaderId, shaderData, shaderDataLen, shaderEnv);\n> +}\n> +\n> +int eGL::compileFragmentShader(GLuint &shaderId, unsigned char *shaderData,\n> +\t\t\t       unsigned int shaderDataLen,\n> +\t\t\t       std::vector<std::string> shaderEnv)\n> +{\n> +\treturn compileShader(GL_FRAGMENT_SHADER, shaderId, shaderData, shaderDataLen, shaderEnv);\n> +}\n> +\n> +int eGL::compileShader(int shaderType, GLuint &shaderId, unsigned char *shaderData,\n> +\t\t       unsigned int shaderDataLen,\n> +\t\t       std::vector<std::string> shaderEnv)\n> +{\n> +\tGLchar **shaderSourceData;\n> +\tGLint *shaderDataLengths;\n> +\tGLint success;\n> +\tGLsizei count;\n> +\tsize_t i;\n> +\n> +\tcount = 1 + shaderEnv.size();\n> +\tshaderSourceData = new GLchar *[count];\n> +\tshaderDataLengths = new GLint[count];\n> +\n> +\t// Prefix defines before main body of shader\n> +\tfor (i = 0; i < shaderEnv.size(); i++) {\n> +\t\tshaderSourceData[i] = (GLchar *)shaderEnv[i].c_str();\n> +\t\tshaderDataLengths[i] = shaderEnv[i].length();\n> +\t}\n> +\n> +\t// Now the main body of the shader program\n> +\tshaderSourceData[i] = (GLchar *)shaderData;\n> +\tshaderDataLengths[i] = shaderDataLen;\n> +\n> +\t// And create the shader\n> +\tshaderId = glCreateShader(shaderType);\n> +\tglShaderSource(shaderId, count, shaderSourceData, shaderDataLengths);\n> +\tglCompileShader(shaderId);\n> +\n> +\t// Check status\n> +\tglGetShaderiv(shaderId, GL_COMPILE_STATUS, &success);\n> +\tif (success == GL_FALSE) {\n> +\t\tGLint sizeLog = 0;\n> +\t\tGLchar *infoLog;\n> +\n> +\t\tglGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &sizeLog);\n> +\t\tinfoLog = new GLchar[sizeLog];\n> +\n> +\t\tglGetShaderInfoLog(shaderId, sizeLog, &sizeLog, infoLog);\n> +\t\tLOG(eGL, Error) << infoLog;\n> +\n> +\t\tdelete[] infoLog;\n> +\t}\n> +\n> +\tdelete[] shaderSourceData;\n> +\tdelete[] shaderDataLengths;\n> +\n> +\treturn !(success == GL_TRUE);\n> +}\n> +\n> +void eGL::dumpShaderSource(GLuint shaderId)\n> +{\n> +\tGLint shaderLength = 0;\n> +\tGLchar *shaderSource;\n> +\n> +\tglGetShaderiv(shaderId, GL_SHADER_SOURCE_LENGTH, &shaderLength);\n> +\n> +\tLOG(eGL, Debug) << \"Shader length is \" << shaderLength;\n> +\n> +\tif (shaderLength > 0) {\n> +\t\tshaderSource = new GLchar[shaderLength];\n> +\t\tif (!shaderSource)\n> +\t\t\treturn;\n> +\n> +\t\tglGetShaderSource(shaderId, shaderLength, &shaderLength, shaderSource);\n> +\t\tif (shaderLength) {\n> +\t\t\tLOG(eGL, Debug) << \"Shader source = \" << shaderSource;\n> +\t\t}\n> +\t\tdelete[] shaderSource;\n> +\t}\n> +}\n> +\n> +int eGL::linkProgram(GLuint &programId, GLuint vertexshaderId, GLuint fragmentshaderId)\n> +{\n> +\tGLint success;\n> +\tGLenum err;\n> +\n> +\tprogramId = glCreateProgram();\n> +\tif (!programId)\n> +\t\tgoto fail;\n> +\n> +\tglAttachShader(programId, vertexshaderId);\n> +\tif ((err = glGetError()) != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Attach compute vertex shader fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglAttachShader(programId, fragmentshaderId);\n> +\tif ((err = glGetError()) != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Attach compute vertex shader fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglLinkProgram(programId);\n> +\tif ((err = glGetError()) != GL_NO_ERROR) {\n> +\t\tLOG(eGL, Error) << \"Link program fail\";\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\tglDetachShader(programId, fragmentshaderId);\n> +\tglDetachShader(programId, vertexshaderId);\n> +\n> +\t// Check status\n> +\tglGetProgramiv(programId, GL_LINK_STATUS, &success);\n> +\tif (success == GL_FALSE) {\n> +\t\tGLint sizeLog = 0;\n> +\t\tGLchar *infoLog;\n> +\n> +\t\tglGetProgramiv(programId, GL_INFO_LOG_LENGTH, &sizeLog);\n> +\t\tinfoLog = new GLchar[sizeLog];\n> +\n> +\t\tglGetProgramInfoLog(programId, sizeLog, &sizeLog, infoLog);\n> +\t\tLOG(eGL, Error) << infoLog;\n> +\n> +\t\tdelete[] infoLog;\n> +\t\tgoto fail;\n> +\t}\n> +\n> +\treturn 0;\n> +fail:\n> +\treturn -ENODEV;\n> +}\n> +} // namespace libcamera\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 64270b571cea2ece8d4dfea8a23b8edf60de70d3..705c328a27f68377573916a77573335f4f4ab3cc 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -78,6 +78,27 @@ if libgbm.found() and gbm_works\n>       ])\n>   endif\n>   \n> +libegl = cc.find_library('EGL', required : false)\n> +libglesv2 = cc.find_library('GLESv2', required : false)\n> +mesa_works = cc.check_header('EGL/egl.h', required: false)\n> +\n> +if libegl.found() and mesa_works\n> +    config_h.set('HAVE_LIBEGL', 1)\n> +endif\n> +\n> +if libglesv2.found() and mesa_works\n> +    config_h.set('HAVE_GLESV2', 1)\n> +endif\n> +\n> +if mesa_works and gbm_works\n> +    libcamera_internal_sources += files([\n> +        'egl.cpp',\n> +    ])\n> +    gles_headless_enabled = true\n> +else\n> +    gles_headless_enabled = false\n> +endif\n> +\n>   subdir('base')\n>   subdir('converter')\n>   subdir('ipa')\n> @@ -191,7 +212,9 @@ libcamera_deps += [\n>       libcamera_base_private,\n>       libcrypto,\n>       libdl,\n> +    libegl,\n>       libgbm,\n> +    libglesv2,\n>       liblttng,\n>       libudev,\n>       libyaml,\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E8B7ABEFBE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 31 Aug 2025 13:59:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1701D69322;\n\tSun, 31 Aug 2025 15:59:09 +0200 (CEST)","from sender4-op-o12.zoho.com (sender4-op-o12.zoho.com\n\t[136.143.188.12])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1CE91613AD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 31 Aug 2025 15:59:05 +0200 (CEST)","by mx.zohomail.com with SMTPS id 175664873855241.46216120771476;\n\tSun, 31 Aug 2025 06:58:58 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"Gn5UrLOA\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1756648742; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=X+a/qdfFv2NmV0Y58vSTavaBiXTfZvNJLTKwtRcxzC+myvObI79uLby2Xk8XpN6NeGb6Q5hXhJZlNd+yA4AjpVl8pW5bqMCzefJyhxADNIsil5v566NxYo6hMiLaEHsyAfxGzdGINenjO2bP+fYMWjLPXamppG+FQO0l33i13DM=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1756648742;\n\th=Content-Type:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To:Cc;\n\tbh=W+xyLRlc2352CPxLOJ/Yrsg7BLHfww1UwDr/Z6cnSSY=; \n\tb=Qg/+1CRQCTudcb4U5Dq5OTIoYOZSt49zSNsd2bN3JdO8qLgfB2rJeZLuc50DMIe4ozicGOVF++QgItKr3Tb9veLYz5Z11cD3AYgv4VY1x5d0/fvj6bsvBrn5a7bnWTDbYKa+EcipEyTJE47AW2JUc3NQGsb07AfkJeoVszyvW4E=","ARC-Authentication-Results":"i=1; mx.zohomail.com;\n\tdkim=pass  header.i=collabora.com;\n\tspf=pass  smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1756648742;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Content-Type:Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:References:From:From:In-Reply-To:Message-Id:Reply-To:Cc;\n\tbh=W+xyLRlc2352CPxLOJ/Yrsg7BLHfww1UwDr/Z6cnSSY=;\n\tb=Gn5UrLOAgyYf+ByumhpP5DdHqqX2l38yFzMFmGrBih2yvw6l+bPdz+W9nn4H6H47\n\tBpv13TAL9Ja2ym9S0JFYSYRQ4rQ3yVgztyrllp24oEEHcXm1qW/x7X2f/kMG2189Jpq\n\tK+fcjcFU30yFaayMAETdLxKECfvE/gkq5w0PvLSE=","Content-Type":"multipart/alternative;\n\tboundary=\"------------l6OYGUcpRUfgTmKLXeHuMSqM\"","Message-ID":"<2e3f64d5-982f-4c5f-9443-5db915a37dff@collabora.com>","Date":"Sun, 31 Aug 2025 15:58:55 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"libcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>","Content-Language":"en-US, de-DE, en-GB","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35646,"web_url":"https://patchwork.libcamera.org/comment/35646/","msgid":"<fa46f0d0-d4f6-47db-81d1-338780490c1b@collabora.com>","date":"2025-08-31T14:56:00","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"On 31.08.25 15:58, Robert Mader wrote:\n>\n> I think there are several issue here:\n>\n>  1. eglClientWaitSyncKHR() with a 0 flag - i.e. no wait condition - is\n>     a no-op.\n>  2. The only supported flag in Mesa is EGL_SYNC_FLUSH_COMMANDS_BIT_KHR\n>     and all it does is triggering a flush if needed - i.e. it should\n>     be equivalent to the glFlush() above if I'm not mistaken.\n>     (https://gitlab.freedesktop.org/mesa/mesa/-/blob/9a03aee7035e7f474ac33edc92954d45e68670e4/src/egl/drivers/dri2/egl_dri2.c#L2932-2963)\n>  3. Flushing alone does not guarantee that the work has actually\n>     completed, but only that the commands have been send to the GPU.\n>     That means the output buffer might still not be ready for\n>     consumption after this command. This is no problem in cases where\n>     the buffer gets imported into GL/VK/V4L2 etc. by the client -\n>     assuming a driver with implicit sync support - but can be an issue\n>     if the buffer is used by a client without implicit sync support -\n>     most importantly when reading from CPU / mmapping. Note that\n>     DMA_BUF_IOCTL_SYNC (which a client is expected to use in this\n>     case) explicitly does *not* cover implicit sync, see the quote\n>     below. If I'm not mistaken the only clean solution here - without\n>     essentially breaking API and requiring consumers to support\n>     implicit sync - is to explicitly wait for the buffer-write to be\n>     complete before handing over to the client. And the best option I\n>     see for that is dma_buf_export_sync_file\n>     <https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file>\n>\n>  4. If we introduce such waiting, it'll probably make sense to ensure\n>     that work on the next buffer can already begin - i.e. we'd want\n>     things to become more async.\n>\n> Regards,\n>\n> Robert\n>\nHm, actually calling glFinish() should do the trick IIUC (instead of \nusing dma_buf_export_sync_file).\n\n> glFinish does not return until the effects of all previously called GL \n> commands are complete. Such effects include all changes to GL state, \n> all changes to connection state, and all changes to the frame buffer \n> contents.","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 11CD6BD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 31 Aug 2025 14:56:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DB17869322;\n\tSun, 31 Aug 2025 16:56:13 +0200 (CEST)","from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com\n\t[136.143.188.112])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F2FDD613AD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 31 Aug 2025 16:56:11 +0200 (CEST)","by mx.zohomail.com with SMTPS id 1756652164466101.51355904510228; \n\tSun, 31 Aug 2025 07:56:04 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"dZiq5TB4\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1756652167; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=EIDxTGOoGFctOVXDVd1ciae5Gd1tqwRkTwYUrgKQipB6q+OHIwl0Foh4Nwb8dSqGco8SZsrorTLRfnTEvM6nTM+ZVP6L9igFAfOflFUIItfjDCfxCLO/jln47vtqqQQA4MXlJNn+0oFutx9ZK8Zk5yNvJuZupsEFYXIM6OQ9XQQ=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1756652167;\n\th=Content-Type:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To:Cc;\n\tbh=Qw914RCCBzgboUhjFq20E9wXwRNFj8m0Od49Zjq/Szw=; \n\tb=QHXoU7La81PkyXB5ZhO7rBYLg4iUtMCCqmNPXxiWE6Y7nQbEERTmtWHjtRD/R5xi7DMv9Kb7a6QU50K6ZXx7TNthMIFH6nDgmgyqfpC76DyBx+iSIApykh5DTI5qAWFIClSbnRXckUprVn0y85VYReopfzbG+lgcS0eqztIqQDI=","ARC-Authentication-Results":"i=1; mx.zohomail.com;\n\tdkim=pass  header.i=collabora.com;\n\tspf=pass  smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1756652167;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Content-Type:Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:References:From:From:In-Reply-To:Message-Id:Reply-To:Cc;\n\tbh=Qw914RCCBzgboUhjFq20E9wXwRNFj8m0Od49Zjq/Szw=;\n\tb=dZiq5TB49CuJIyPKLX85q64oiFMzegozH0hAn3GVNIqPRxGw/njxi7jrVNUWxkYZ\n\tUfwGYK+1bdaMfgRnZAs5uXRi/T9C6VY1vX87QetY0uILH5a4O2cp41sh/U4Qj7nzxt+\n\tp/ebsE3K4JBdEacAtmJ5T8milf61+hWpLDv4Ss6Q=","Content-Type":"multipart/alternative;\n\tboundary=\"------------LcedBsBvaKyTnXuLCMNT0BC6\"","Message-ID":"<fa46f0d0-d4f6-47db-81d1-338780490c1b@collabora.com>","Date":"Sun, 31 Aug 2025 16:56:00 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"libcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>\n\t<2e3f64d5-982f-4c5f-9443-5db915a37dff@collabora.com>","Content-Language":"en-US, de-DE, en-GB","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<2e3f64d5-982f-4c5f-9443-5db915a37dff@collabora.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35648,"web_url":"https://patchwork.libcamera.org/comment/35648/","msgid":"<09e09bba-4057-4aa8-97e8-4255c0c6c7e4@collabora.com>","date":"2025-08-31T15:26:41","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":140,"url":"https://patchwork.libcamera.org/api/people/140/","name":"Robert Mader","email":"robert.mader@collabora.com"},"content":"Urgh, I was wrong, sorry for the noise. EGL_SYNC_FENCE_KHR implies \nEGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR, which again should block until \nwriting to the buffer is complete. So this is all correct.\n\nThe only comment I've left is that since syncOutput() is called in \ndebayerGPU(), making sure that stats_->processFrame() can run in another \nthread in parallel, as mentioned in another mail before, would likely be \na worthwhile optimization.\n\nOn 31.08.25 16:56, Robert Mader wrote:\n> On 31.08.25 15:58, Robert Mader wrote:\n>>\n>> I think there are several issue here:\n>>\n>>  1. eglClientWaitSyncKHR() with a 0 flag - i.e. no wait condition -\n>>     is a no-op.\n>>  2. The only supported flag in Mesa is\n>>     EGL_SYNC_FLUSH_COMMANDS_BIT_KHR and all it does is triggering a\n>>     flush if needed - i.e. it should be equivalent to the glFlush()\n>>     above if I'm not mistaken.\n>>     (https://gitlab.freedesktop.org/mesa/mesa/-/blob/9a03aee7035e7f474ac33edc92954d45e68670e4/src/egl/drivers/dri2/egl_dri2.c#L2932-2963)\n>>  3. Flushing alone does not guarantee that the work has actually\n>>     completed, but only that the commands have been send to the GPU.\n>>     That means the output buffer might still not be ready for\n>>     consumption after this command. This is no problem in cases where\n>>     the buffer gets imported into GL/VK/V4L2 etc. by the client -\n>>     assuming a driver with implicit sync support - but can be an\n>>     issue if the buffer is used by a client without implicit sync\n>>     support - most importantly when reading from CPU / mmapping. Note\n>>     that DMA_BUF_IOCTL_SYNC (which a client is expected to use in\n>>     this case) explicitly does *not* cover implicit sync, see the\n>>     quote below. If I'm not mistaken the only clean solution here -\n>>     without essentially breaking API and requiring consumers to\n>>     support implicit sync - is to explicitly wait for the\n>>     buffer-write to be complete before handing over to the client.\n>>     And the best option I see for that is dma_buf_export_sync_file\n>>     <https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file>\n>>\n>>  4. If we introduce such waiting, it'll probably make sense to ensure\n>>     that work on the next buffer can already begin - i.e. we'd want\n>>     things to become more async.\n>>\n>> Regards,\n>>\n>> Robert\n>>\n> Hm, actually calling glFinish() should do the trick IIUC (instead of \n> using dma_buf_export_sync_file).\n>\n>> glFinish does not return until the effects of all previously called \n>> GL commands are complete. Such effects include all changes to GL \n>> state, all changes to connection state, and all changes to the frame \n>> buffer contents.","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 0EC62BD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 31 Aug 2025 15:26:49 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2449E69322;\n\tSun, 31 Aug 2025 17:26:48 +0200 (CEST)","from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com\n\t[136.143.188.112])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0E036613AD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 31 Aug 2025 17:26:46 +0200 (CEST)","by mx.zohomail.com with SMTPS id 1756654003178578.9632349561396;\n\tSun, 31 Aug 2025 08:26:43 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=collabora.com\n\theader.i=robert.mader@collabora.com header.b=\"C3aFw3nc\"; \n\tdkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1756654004; cv=none; \n\td=zohomail.com; s=zohoarc; \n\tb=j9NIWXIiUsFH9fgGYESBEEAYvC77U6hjQ9wWAzr44UmqvKWuL5q1c19VqKgyICM07zDXnBJWDZMot/XdKCcFh4x9Pv1CRnWFGniiObO9WHXvZ4SY2leP+bAIT8flHS38oJ27AP0JjPirOYhVYecsnald03wn+G+RkRVYhZAITnY=","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; \n\ts=zohoarc; t=1756654004;\n\th=Content-Type:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To:Cc;\n\tbh=bQdGr4VmaVCUExUsFWNtIKigHXbqaYRXAD51obprqec=; \n\tb=AOFkRXeBR8R005qmSzJlSlWJiSkyhwedsveemUidb1DJOaAw6vUZv6aQ0ZGbDG6zSES9irdmhx++JOM4U+VG5tgPmthBln5R/DK+2qxRMS7EBf+2BHdMt4eeFAxXNR8CnsGlT6Z1Qas8auuOi80kXpzLRA8e2hH1Itn67czTh5k=","ARC-Authentication-Results":"i=1; mx.zohomail.com;\n\tdkim=pass  header.i=collabora.com;\n\tspf=pass  smtp.mailfrom=robert.mader@collabora.com;\n\tdmarc=pass header.from=<robert.mader@collabora.com>","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1756654004;\n\ts=zohomail; d=collabora.com; i=robert.mader@collabora.com;\n\th=Content-Type:Message-ID:Date:Date:MIME-Version:Subject:Subject:To:To:References:From:From:In-Reply-To:Message-Id:Reply-To:Cc;\n\tbh=bQdGr4VmaVCUExUsFWNtIKigHXbqaYRXAD51obprqec=;\n\tb=C3aFw3ncmOiA1aCoUIKKr63CaTlgcwBnaLTWh9eGoxSFdHglbMvIPePftbhLqEay\n\tp077G07ufL7gqyyyZ5SunW2//jRU7+wqgioLdmq/Wj4wkeU92d3XDdCQqwrnEHmuvlv\n\tu+4nuwsw17zDclVlRhcrjDIPhjJIi4j+7AqUtI8I=","Content-Type":"multipart/alternative;\n\tboundary=\"------------OPqf8GUjP3iA7kWvDfKtZMUB\"","Message-ID":"<09e09bba-4057-4aa8-97e8-4255c0c6c7e4@collabora.com>","Date":"Sun, 31 Aug 2025 17:26:41 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"libcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>\n\t<2e3f64d5-982f-4c5f-9443-5db915a37dff@collabora.com>\n\t<fa46f0d0-d4f6-47db-81d1-338780490c1b@collabora.com>","Content-Language":"en-US, de-DE, en-GB","From":"Robert Mader <robert.mader@collabora.com>","In-Reply-To":"<fa46f0d0-d4f6-47db-81d1-338780490c1b@collabora.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":36142,"web_url":"https://patchwork.libcamera.org/comment/36142/","msgid":"<405f8c35-df95-401d-a452-ca1c09e252cd@nxsw.ie>","date":"2025-10-06T11:49:18","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 28/08/2025 22:35, Robert Mader wrote:\n>> +\t\tEGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)eglImage->stride_,\n>> +\t\tEGL_NONE, EGL_NONE,\t/* modifier lo */\n>> +\t\tEGL_NONE, EGL_NONE,\t/* modifier hi */\n> \n> These two cause eglCreateImageKHR() to fail on this platform. Simply \n> replacing it with\n> \n>          EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, 0,\n>          EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, 0,\n> \n> does the trick, though.\n> \n\nTook that change in as-is.\n\n---\nbod","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 30D88C324C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  6 Oct 2025 11:49:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CD8F96B5F3;\n\tMon,  6 Oct 2025 13:49:24 +0200 (CEST)","from tor.source.kernel.org (tor.source.kernel.org\n\t[IPv6:2600:3c04:e001:324:0:1991:8:25])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 26BE26936E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  6 Oct 2025 13:49:23 +0200 (CEST)","from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58])\n\tby tor.source.kernel.org (Postfix) with ESMTP id 834F160460\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  6 Oct 2025 11:49:21 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id A1182C4CEF5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  6 Oct 2025 11:49:20 +0000 (UTC)"],"Message-ID":"<405f8c35-df95-401d-a452-ca1c09e252cd@nxsw.ie>","Date":"Mon, 6 Oct 2025 12:49:18 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"libcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>\n\t<yBI2iMUTqjp2Vm0NM5B5cCi_Bfphdk4gUxGE7YXOw1UUa2fgQYXxTkASFKn1AHLno3uiGp6NpYsliE1Gpti_6w==@protonmail.internalid>\n\t<88d54676-48e2-41e6-9fb7-1ab3561382ef@collabora.com>","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Content-Language":"en-US","In-Reply-To":"<88d54676-48e2-41e6-9fb7-1ab3561382ef@collabora.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":36154,"web_url":"https://patchwork.libcamera.org/comment/36154/","msgid":"<aa18a5e0-c84c-4f05-9eec-bc8997c03c8a@nxsw.ie>","date":"2025-10-06T21:06:44","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 31/08/2025 16:26, Robert Mader wrote:\n> The only comment I've left is that since syncOutput() is called in \n> debayerGPU(), making sure that stats_->processFrame() can run in another \n> thread in parallel, as mentioned in another mail before, would likely be \n> a worthwhile optimization.\n> \n\nI'd say further optimisation is the enemy of publishing right now, i.e. \nnot letting the perfect be the enemy of good enough.\n\nI'm going to park the breaking up of processFrame() into another thread \nfor the todo.txt\n\n---\nbod","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 79954BF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  6 Oct 2025 21:06:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 821FE6B5AA;\n\tMon,  6 Oct 2025 23:06:51 +0200 (CEST)","from mail-4323.protonmail.ch (mail-4323.protonmail.ch\n\t[185.70.43.23])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B241A6936E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  6 Oct 2025 23:06:49 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxsw.ie header.i=@nxsw.ie header.b=\"cIs5hrpx\";\n\tdkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxsw.ie;\n\ts=protonmail3; t=1759784808; x=1760044008;\n\tbh=DPtU5svHbsvnJCGmbQmKYYkEcVPdc7G8JrCB/16dft0=;\n\th=Date:To:From:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector;\n\tb=cIs5hrpxoWz6zJgb57qO+hDm5qJ1ZXWKKTYMT41PZlY3R+NoOJu5ftjIvoeq6igcn\n\t+YUyzs5JxxIJ0U3ZdxhRbsePgBoVxJb1IDHFjFWKzeHfRXFgtGe+P4aO2H1dUUK5bJ\n\t/A932d0QcJgPuz1xEDHq8OBx/+fs6yJA7NcRF4TM10qjEXJdZizunKQDjju+LE0tqm\n\t+DjxnAw+dv/XcTG9l6i8gsLSE4u0lsb9FK0taoRgqHAOMimtjos2nMo+N/s+KGwsda\n\tXYtqJ1hL4F131nJIti4UOqGukgxDsDIp02HCBh3I4qsV6sNf5D5jj1jDRWwJl/5cPA\n\tWEuwEUWKe6hWg==","Date":"Mon, 06 Oct 2025 21:06:44 +0000","To":"Robert Mader <robert.mader@collabora.com>,\n\tlibcamera-devel@lists.libcamera.org","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","Message-ID":"<aa18a5e0-c84c-4f05-9eec-bc8997c03c8a@nxsw.ie>","In-Reply-To":"<09e09bba-4057-4aa8-97e8-4255c0c6c7e4@collabora.com>","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>\n\t<2e3f64d5-982f-4c5f-9443-5db915a37dff@collabora.com>\n\t<fa46f0d0-d4f6-47db-81d1-338780490c1b@collabora.com>\n\t<09e09bba-4057-4aa8-97e8-4255c0c6c7e4@collabora.com>","Feedback-ID":"136405006:user:proton","X-Pm-Message-ID":"c7ed2053894b3330ed3025b5dfe1fcfc18210377","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":36168,"web_url":"https://patchwork.libcamera.org/comment/36168/","msgid":"<308cd45c-6ee5-4a16-817c-652f37665b52@ideasonboard.com>","date":"2025-10-07T11:30:59","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n\n2025. 08. 24. 2:48 keltezéssel, Bryan O'Donoghue írta:\n> Introduce an eGL base helper class which provides an eGL context based on a\n> passed width and height.\n> \n> The initGLContext function could be overloaded to provide an interface to a\n> real display.\n> \n> A set of helper functions is provided to compile and link GLSL shaders.\n> linkShaderProgram currently compiles vertex/fragment pairs but could be\n> overloaded or passed a parameter to link a compute shader instead.\n> \n> Breaking the eGL interface away from debayering - allows to use the eGL\n> context inside of a dma-buf heap cleanly, reuse that context inside of a\n> debayer layer and conceivably reuse the context in a multi-stage shader\n> pass.\n> \n> Small note the image_attrs[] array doesn't pass checkstyle.py however the\n> elements of the array are in pairs.\n> \n> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>\n> ---\n\nI was wondering if you had a chance to look at my earlier comments\n( https://lists.libcamera.org/pipermail/libcamera-devel/2025-June/050895.html )?\n\n\nRegards,\nBarnabás Pőcze\n\n\n>   include/libcamera/internal/egl.h | 133 +++++++++++++\n>   src/libcamera/egl.cpp            | 408 +++++++++++++++++++++++++++++++++++++++\n>   src/libcamera/meson.build        |  23 +++\n>   3 files changed, 564 insertions(+)\n> \n> [...]","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 53DD2BF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  7 Oct 2025 11:31:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9B29069367;\n\tTue,  7 Oct 2025 13:31:05 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0BFC569367\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  7 Oct 2025 13:31:03 +0200 (CEST)","from [192.168.33.24] (185.182.214.142.nat.pool.zt.hu\n\t[185.182.214.142])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C4E7C56D;\n\tTue,  7 Oct 2025 13:29:29 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"owf2IAa2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1759836569;\n\tbh=nYVay2Bp7qTbkXDLFcI4qzIsU4VALU+4hodCxqnsrkI=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=owf2IAa2tYto85qW1pl2un8XPdvJvhURnxZ7CDh9k+7wU+j/29sClr0QAXlqCgTDL\n\tys9Ba+85D0x/DT2tQf4nCtL5M8RD9IlrRErjqkNj/xd08TE1CnV/D1C87XMJ583ZIQ\n\tgK0c6fIsU+OaDA8B9TPpJw2sZsAChAf0yxUg/96c=","Message-ID":"<308cd45c-6ee5-4a16-817c-652f37665b52@ideasonboard.com>","Date":"Tue, 7 Oct 2025 13:30:59 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"Bryan O'Donoghue <bryan.odonoghue@linaro.org>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":36169,"web_url":"https://patchwork.libcamera.org/comment/36169/","msgid":"<d23bb138-94ca-490a-a52d-753fe60fcd53@nxsw.ie>","date":"2025-10-07T11:42:19","subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","submitter":{"id":226,"url":"https://patchwork.libcamera.org/api/people/226/","name":"Bryan O'Donoghue","email":"bod.linux@nxsw.ie"},"content":"On 07/10/2025 12:30, Barnabás Pőcze wrote:\n> I was wondering if you had a chance to look at my earlier comments\n> (https://lists.libcamera.org/pipermail/libcamera-devel/2025-June/050895.html )?\n> \n\nAh I think I was trying to mentally block it out ... :)\n\nI will go through the remainder and try to digest the rest of this.\n\n---\nbod","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 3EEFCC324C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  7 Oct 2025 11:42:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C94C36B5F3;\n\tTue,  7 Oct 2025 13:42:26 +0200 (CEST)","from sea.source.kernel.org (sea.source.kernel.org [172.234.252.31])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6716E69367\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  7 Oct 2025 13:42:24 +0200 (CEST)","from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58])\n\tby sea.source.kernel.org (Postfix) with ESMTP id 76C0B4184D;\n\tTue,  7 Oct 2025 11:42:22 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id 97E82C4CEF9;\n\tTue,  7 Oct 2025 11:42:21 +0000 (UTC)"],"Message-ID":"<d23bb138-94ca-490a-a52d-753fe60fcd53@nxsw.ie>","Date":"Tue, 7 Oct 2025 12:42:19 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2 24/37] libcamera: software_isp: egl: Introduce an eGL\n\tbase helper class","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tBryan O'Donoghue <bryan.odonoghue@linaro.org>, \n\tlibcamera-devel@lists.libcamera.org","References":"<20250824-b4-v0-5-2-gpuisp-v2-a-v2-0-96f4576c814e@linaro.org>\n\t<20250824-b4-v0-5-2-gpuisp-v2-a-v2-24-96f4576c814e@linaro.org>\n\t<BByqhHuQp4FYlLmdUWwDryfdTcsB4XlNTdQXYtaqwF3KcgN1_Regr3aEhz2MBkmvBYNZEBy-kpz4Npn-ELOEsQ==@protonmail.internalid>\n\t<308cd45c-6ee5-4a16-817c-652f37665b52@ideasonboard.com>","From":"Bryan O'Donoghue <bod.linux@nxsw.ie>","Content-Language":"en-US","In-Reply-To":"<308cd45c-6ee5-4a16-817c-652f37665b52@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]