testffmpeg: Use EGL_EXT_image_dma_buf_import_modifiers extension

If the `EGL_EXT_image_dma_buf_import_modifiers` extension is available, propagate the DRM format modifier from the AVDRMObjectDescriptor to eglCreateImage() on Linux. Some hardware will decode video into a non-linear DRM surface, and passing the DRM format modifier to eglCreateImage() is required in order to display something useful.

Fixes https://github.com/libsdl-org/SDL/issues/9075
This commit is contained in:
Robert Edmonds 2024-03-03 17:46:14 -05:00 committed by Sam Lantinga
parent ae4484f4e5
commit a4d7ff6751

View File

@ -73,6 +73,7 @@ static SDL_bool software_only;
static SDL_bool has_eglCreateImage;
#ifdef HAVE_EGL
static SDL_bool has_EGL_EXT_image_dma_buf_import;
static SDL_bool has_EGL_EXT_image_dma_buf_import_modifiers;
static PFNGLACTIVETEXTUREARBPROC glActiveTextureARBFunc;
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOESFunc;
#endif
@ -137,11 +138,32 @@ static SDL_bool CreateWindowAndRenderer(Uint32 window_flags, const char *driver)
#ifdef HAVE_EGL
if (useEGL) {
const char *extensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
if (SDL_strstr(extensions, "EGL_EXT_image_dma_buf_import") != NULL) {
has_EGL_EXT_image_dma_buf_import = SDL_TRUE;
const char *egl_extensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
if (!egl_extensions) {
return SDL_FALSE;
}
char *extensions = SDL_strdup(egl_extensions);
if (!extensions) {
return SDL_FALSE;
}
char *saveptr, *token;
token = SDL_strtok_r(extensions, " ", &saveptr);
if (!token) {
free(extensions);
return SDL_FALSE;
}
do {
if (SDL_strcmp(token, "EGL_EXT_image_dma_buf_import") == 0) {
has_EGL_EXT_image_dma_buf_import = SDL_TRUE;
} else if (SDL_strcmp(token, "EGL_EXT_image_dma_buf_import_modifiers") == 0) {
has_EGL_EXT_image_dma_buf_import_modifiers = SDL_TRUE;
}
} while ((token = SDL_strtok_r(NULL, " ", &saveptr)) != NULL);
free(extensions);
if (SDL_GL_ExtensionSupported("GL_OES_EGL_image")) {
glEGLImageTargetTexture2DOESFunc = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
}
@ -609,16 +631,39 @@ static SDL_bool GetTextureForDRMFrame(AVFrame *frame, SDL_Texture **texture)
static const uint32_t formats[ 2 ] = { DRM_FORMAT_R8, DRM_FORMAT_GR88 };
const AVDRMPlaneDescriptor *plane = &layer->planes[j];
const AVDRMObjectDescriptor *object = &desc->objects[plane->object_index];
EGLAttrib img_attr[] = {
EGL_LINUX_DRM_FOURCC_EXT, formats[i],
EGL_WIDTH, frame->width / ( image_index + 1 ), /* half size for chroma */
EGL_HEIGHT, frame->height / ( image_index + 1 ),
EGL_DMA_BUF_PLANE0_FD_EXT, object->fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, plane->offset,
EGL_DMA_BUF_PLANE0_PITCH_EXT, plane->pitch,
EGL_NONE
};
EGLImage pImage = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, img_attr);
EGLAttrib attr[32];
size_t k = 0;
attr[k++] = EGL_LINUX_DRM_FOURCC_EXT;
attr[k++] = formats[i];
attr[k++] = EGL_WIDTH;
attr[k++] = frame->width / ( image_index + 1 ); /* half size for chroma */
attr[k++] = EGL_HEIGHT;
attr[k++] = frame->height / ( image_index + 1 );
attr[k++] = EGL_DMA_BUF_PLANE0_FD_EXT;
attr[k++] = object->fd;
attr[k++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
attr[k++] = plane->offset;
attr[k++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
attr[k++] = plane->pitch;
if (has_EGL_EXT_image_dma_buf_import_modifiers) {
attr[k++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
attr[k++] = (object->format_modifier >> 0) & 0xFFFFFFFF;
attr[k++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
attr[k++] = (object->format_modifier >> 32) & 0xFFFFFFFF;
}
attr[k++] = EGL_NONE;
EGLImage pImage = eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr);
glActiveTextureARBFunc(GL_TEXTURE0_ARB + image_index);
glBindTexture(GL_TEXTURE_2D, textures[image_index]);