mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-04-23 00:19:40 +00:00
Export composed VA surface layers for EGL import if supported
Importing composed formats is more efficient and performant because it allows tiled and/or compressed surfaces to be directly sampled by shaders without requiring a conversion to a linear planar format first.
This commit is contained in:
@@ -1,9 +1,21 @@
|
||||
#include "eglimagefactory.h"
|
||||
|
||||
// Don't take a dependency on libdrm just for this constant
|
||||
// Don't take a dependency on libdrm just for these constants
|
||||
#ifndef DRM_FORMAT_MOD_INVALID
|
||||
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_MOD_LINEAR
|
||||
#define DRM_FORMAT_MOD_LINEAR 0
|
||||
#endif
|
||||
#ifndef fourcc_code
|
||||
#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_R8
|
||||
#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_GR88
|
||||
#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8')
|
||||
#endif
|
||||
|
||||
EglImageFactory::EglImageFactory(IFFmpegRenderer* renderer) :
|
||||
m_Renderer(renderer),
|
||||
@@ -11,7 +23,9 @@ EglImageFactory::EglImageFactory(IFFmpegRenderer* renderer) :
|
||||
m_eglCreateImage(nullptr),
|
||||
m_eglDestroyImage(nullptr),
|
||||
m_eglCreateImageKHR(nullptr),
|
||||
m_eglDestroyImageKHR(nullptr)
|
||||
m_eglDestroyImageKHR(nullptr),
|
||||
m_eglQueryDmaBufFormatsEXT(nullptr),
|
||||
m_eglQueryDmaBufModifiersEXT(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -25,6 +39,10 @@ bool EglImageFactory::initializeEGL(EGLDisplay,
|
||||
}
|
||||
|
||||
m_EGLExtDmaBuf = ext.isSupported("EGL_EXT_image_dma_buf_import_modifiers");
|
||||
if (m_EGLExtDmaBuf) {
|
||||
m_eglQueryDmaBufFormatsEXT = (typeof(m_eglQueryDmaBufFormatsEXT))eglGetProcAddress("eglQueryDmaBufFormatsEXT");
|
||||
m_eglQueryDmaBufModifiersEXT = (typeof(m_eglQueryDmaBufModifiersEXT))eglGetProcAddress("eglQueryDmaBufModifiersEXT");
|
||||
}
|
||||
|
||||
// NB: eglCreateImage() and eglCreateImageKHR() have slightly different definitions
|
||||
m_eglCreateImage = (typeof(m_eglCreateImage))eglGetProcAddress("eglCreateImage");
|
||||
@@ -42,6 +60,8 @@ bool EglImageFactory::initializeEGL(EGLDisplay,
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DRM
|
||||
|
||||
ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, AVDRMFrameDescriptor* drmFrame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES])
|
||||
{
|
||||
memset(images, 0, sizeof(EGLImage) * EGL_MAX_PLANES);
|
||||
@@ -216,9 +236,11 @@ ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, AVDRMFrameDescriptor* d
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBVA
|
||||
|
||||
ssize_t EglImageFactory::exportVAImages(AVFrame *frame, VADRMPRIMESurfaceDescriptor *vaFrame, EGLDisplay dpy, EGLImage images[])
|
||||
ssize_t EglImageFactory::exportVAImages(AVFrame *frame, VADRMPRIMESurfaceDescriptor *vaFrame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES])
|
||||
{
|
||||
ssize_t count = 0;
|
||||
|
||||
@@ -229,8 +251,8 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, VADRMPRIMESurfaceDescrip
|
||||
for (size_t i = 0; i < vaFrame->num_layers; ++i) {
|
||||
const auto &layer = vaFrame->layers[i];
|
||||
|
||||
// Max 31 attributes (1 key + 1 value for each)
|
||||
const int EGL_ATTRIB_COUNT = 31 * 2;
|
||||
// Max 33 attributes (1 key + 1 value for each)
|
||||
const int EGL_ATTRIB_COUNT = 33 * 2;
|
||||
EGLAttrib attribs[EGL_ATTRIB_COUNT] = {
|
||||
EGL_LINUX_DRM_FOURCC_EXT, layer.drm_format,
|
||||
EGL_WIDTH, i == 0 ? frame->width : frame->width / 2,
|
||||
@@ -308,6 +330,61 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, VADRMPRIMESurfaceDescrip
|
||||
}
|
||||
}
|
||||
|
||||
// For composed exports, add the YUV metadata
|
||||
if (vaFrame->num_layers == 1) {
|
||||
// Add colorspace metadata
|
||||
switch (m_Renderer->getFrameColorspace(frame)) {
|
||||
case COLORSPACE_REC_601:
|
||||
attribs[attribIndex++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_ITU_REC601_EXT;
|
||||
break;
|
||||
case COLORSPACE_REC_709:
|
||||
attribs[attribIndex++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_ITU_REC709_EXT;
|
||||
break;
|
||||
case COLORSPACE_REC_2020:
|
||||
attribs[attribIndex++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_ITU_REC2020_EXT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Add color range metadata
|
||||
attribs[attribIndex++] = EGL_SAMPLE_RANGE_HINT_EXT;
|
||||
attribs[attribIndex++] = m_Renderer->isFrameFullRange(frame) ? EGL_YUV_FULL_RANGE_EXT : EGL_YUV_NARROW_RANGE_EXT;
|
||||
|
||||
// Add chroma siting metadata
|
||||
switch (frame->chroma_location) {
|
||||
case AVCHROMA_LOC_LEFT:
|
||||
case AVCHROMA_LOC_TOPLEFT:
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_SITING_0_EXT;
|
||||
break;
|
||||
|
||||
case AVCHROMA_LOC_CENTER:
|
||||
case AVCHROMA_LOC_TOP:
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_SITING_0_5_EXT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (frame->chroma_location) {
|
||||
case AVCHROMA_LOC_TOPLEFT:
|
||||
case AVCHROMA_LOC_TOP:
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_SITING_0_EXT;
|
||||
break;
|
||||
|
||||
case AVCHROMA_LOC_LEFT:
|
||||
case AVCHROMA_LOC_CENTER:
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT;
|
||||
attribs[attribIndex++] = EGL_YUV_CHROMA_SITING_0_5_EXT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate the attribute list
|
||||
attribs[attribIndex++] = EGL_NONE;
|
||||
SDL_assert(attribIndex <= EGL_ATTRIB_COUNT);
|
||||
@@ -341,6 +418,7 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, VADRMPRIMESurfaceDescrip
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
fail:
|
||||
@@ -348,6 +426,77 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool EglImageFactory::supportsImportingFormat(EGLDisplay dpy, EGLint format)
|
||||
{
|
||||
if (!m_eglQueryDmaBufFormatsEXT) {
|
||||
// These are the standard formats used for importing separate layers of NV12.
|
||||
// We will assume all EGL implementations can handle these.
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Assuming R8 and GR88 format support because eglQueryDmaBufFormatsEXT() is not supported");
|
||||
return format == DRM_FORMAT_R8 || format == DRM_FORMAT_GR88;
|
||||
}
|
||||
|
||||
// Get the number of formats
|
||||
EGLint numFormats;
|
||||
if (!m_eglQueryDmaBufFormatsEXT(dpy, 0, nullptr, &numFormats)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"eglQueryDmaBufFormatsEXT() #1 failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLint formats[numFormats];
|
||||
if (!m_eglQueryDmaBufFormatsEXT(dpy, numFormats, formats, &numFormats)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"eglQueryDmaBufFormatsEXT() #2 failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EGLint i = 0; i < numFormats; i++) {
|
||||
if (format == formats[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EglImageFactory::supportsImportingModifier(EGLDisplay dpy, EGLint format, EGLuint64KHR modifier)
|
||||
{
|
||||
// We assume linear and no modifiers are always supported
|
||||
if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == DRM_FORMAT_MOD_INVALID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_eglQueryDmaBufModifiersEXT) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Assuming linear modifier support because eglQueryDmaBufModifiersEXT() is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the number of modifiers
|
||||
EGLint numModifiers;
|
||||
if (!m_eglQueryDmaBufModifiersEXT(dpy, format, 0, nullptr, nullptr, &numModifiers)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"eglQueryDmaBufModifiersEXT() #1 failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLuint64KHR modifiers[numModifiers];
|
||||
if (!m_eglQueryDmaBufModifiersEXT(dpy, format, numModifiers, modifiers, nullptr, &numModifiers)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"eglQueryDmaBufModifiersEXT() #2 failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EGLint i = 0; i < numModifiers; i++) {
|
||||
if (modifier == modifiers[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void EglImageFactory::freeEGLImages(EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) {
|
||||
@@ -361,4 +510,5 @@ void EglImageFactory::freeEGLImages(EGLDisplay dpy, EGLImage images[EGL_MAX_PLAN
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(images, 0, sizeof(EGLImage) * EGL_MAX_PLANES);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user