mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-02-16 02:30:52 +00:00
Simplify EGLImageFactory and remove caching logic for now
The platforms that would most benefit (embedded V4L2 decoders) either don't use frame pooling or don't synchronize with modified DMA-BUFs unless eglCreateImage() is called each time.
This commit is contained in:
@@ -1497,8 +1497,8 @@ ssize_t DrmRenderer::exportEGLImages(AVFrame *frame, EGLDisplay dpy,
|
||||
return m_EglImageFactory.exportDRMImages(frame, dpy, images);
|
||||
}
|
||||
|
||||
void DrmRenderer::freeEGLImages(EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) {
|
||||
m_EglImageFactory.freeEGLImages(dpy, images);
|
||||
void DrmRenderer::freeEGLImages() {
|
||||
m_EglImageFactory.freeEGLImages();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
virtual AVPixelFormat getEGLImagePixelFormat() override;
|
||||
virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override;
|
||||
virtual ssize_t exportEGLImages(AVFrame *frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) override;
|
||||
virtual void freeEGLImages(EGLDisplay dpy, EGLImage[EGL_MAX_PLANES]) override;
|
||||
virtual void freeEGLImages() override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
EglImageFactory::EglImageFactory(IFFmpegRenderer* renderer) :
|
||||
m_Renderer(renderer),
|
||||
m_CacheDisabled(false),
|
||||
m_EGLExtDmaBuf(false),
|
||||
m_eglCreateImage(nullptr),
|
||||
m_eglDestroyImage(nullptr),
|
||||
@@ -70,72 +69,18 @@ bool EglImageFactory::initializeEGL(EGLDisplay,
|
||||
|
||||
void EglImageFactory::resetCache()
|
||||
{
|
||||
m_CachedImages.clear();
|
||||
}
|
||||
|
||||
ssize_t EglImageFactory::queryImageCache(AVFrame *frame, EGLImage images[EGL_MAX_PLANES])
|
||||
{
|
||||
if (m_CacheDisabled) {
|
||||
return -1;
|
||||
}
|
||||
else if (!frame->hw_frames_ctx) {
|
||||
// If we don't have a AVHWFramesContext, we won't have a frame pool
|
||||
// which means our caching logic of checking AVBuffer pointers won't
|
||||
// work properly.
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"EGLImage caching disabled due to missing AVHWFramesContext");
|
||||
m_CacheDisabled = true;
|
||||
return -1;
|
||||
}
|
||||
else if (!frame->buf[0]) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"EGLImage caching disabled due to missing AVBufferRef");
|
||||
m_CacheDisabled = true;
|
||||
return -1;
|
||||
}
|
||||
else if (!frame->buf[0]->buffer) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"EGLImage caching disabled due to missing AVBuffer");
|
||||
m_CacheDisabled = true;
|
||||
return -1;
|
||||
}
|
||||
else if (m_CachedImages.size() >= 20) {
|
||||
// This is a final fail-safe for the case where the buffers aren't
|
||||
// actually being reused to avoid the cache size growing forever.
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"EGLImage caching disabled due to excessive cached image count");
|
||||
m_CacheDisabled = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto imgCtx = m_CachedImages.find(frame->buf[0]->buffer);
|
||||
if (imgCtx == m_CachedImages.end()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(images, imgCtx->second.images, sizeof(EGLImage) * imgCtx->second.count);
|
||||
return imgCtx->second.count;
|
||||
}
|
||||
|
||||
void EglImageFactory::populateImageCache(AVFrame *frame, EglImageContext &&imgCtx)
|
||||
{
|
||||
AVBuffer* cacheKey = m_CacheDisabled ? nullptr : frame->buf[0]->buffer;
|
||||
|
||||
// Move this entry into the cache
|
||||
m_CachedImages.emplace(cacheKey, std::move(imgCtx));
|
||||
// Cannot reset cache while in the middle of rendering
|
||||
SDL_assert(!m_LastImageCtx.has_value());
|
||||
}
|
||||
|
||||
#ifdef HAVE_DRM
|
||||
|
||||
ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES])
|
||||
{
|
||||
memset(images, 0, sizeof(EGLImage) * EGL_MAX_PLANES);
|
||||
|
||||
// Check the cache first
|
||||
if (ssize_t count = queryImageCache(frame, images); count > 0) {
|
||||
return count;
|
||||
}
|
||||
// freeEGLImages() must be called before exporting again
|
||||
SDL_assert(!m_LastImageCtx.has_value());
|
||||
|
||||
SDL_assert(frame->format == AV_PIX_FMT_DRM_PRIME);
|
||||
AVDRMFrameDescriptor* drmFrame = (AVDRMFrameDescriptor*)frame->data[0];
|
||||
|
||||
// DRM requires composed layers rather than separate layers per plane
|
||||
@@ -312,8 +257,8 @@ ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, EGLDisplay dpy, EGLImag
|
||||
// Copy the output from the image context before we move it
|
||||
images[0] = imgCtx.images[0];
|
||||
|
||||
// Move this image context into the cache
|
||||
populateImageCache(frame, std::move(imgCtx));
|
||||
// Store this image context
|
||||
m_LastImageCtx.emplace(std::move(imgCtx));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -324,8 +269,10 @@ ssize_t EglImageFactory::exportDRMImages(AVFrame* frame, EGLDisplay dpy, EGLImag
|
||||
|
||||
ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES])
|
||||
{
|
||||
memset(images, 0, sizeof(EGLImage) * EGL_MAX_PLANES);
|
||||
// freeEGLImages() must be called before exporting again
|
||||
SDL_assert(!m_LastImageCtx.has_value());
|
||||
|
||||
SDL_assert(frame->format == AV_PIX_FMT_VAAPI);
|
||||
auto hwFrameCtx = (AVHWFramesContext*)frame->hw_frames_ctx->data;
|
||||
AVVAAPIDeviceContext* vaDeviceContext = (AVVAAPIDeviceContext*)hwFrameCtx->device_ctx->hwctx;
|
||||
VASurfaceID surface_id = (VASurfaceID)(uintptr_t)frame->data[3];
|
||||
@@ -338,11 +285,6 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check the cache first
|
||||
if (ssize_t count = queryImageCache(frame, images); count > 0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
EglImageContext imgCtx(dpy, m_eglDestroyImage, m_eglDestroyImageKHR);
|
||||
|
||||
VADRMPRIMESurfaceDescriptor vaFrame;
|
||||
@@ -544,8 +486,8 @@ ssize_t EglImageFactory::exportVAImages(AVFrame *frame, uint32_t exportFlags, EG
|
||||
ssize_t count = imgCtx.count;
|
||||
memcpy(images, imgCtx.images, sizeof(EGLImage) * imgCtx.count);
|
||||
|
||||
// Move this image context into the cache
|
||||
populateImageCache(frame, std::move(imgCtx));
|
||||
// Store this image context
|
||||
m_LastImageCtx.emplace(std::move(imgCtx));
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -633,13 +575,7 @@ bool EglImageFactory::supportsImportingModifier(EGLDisplay dpy, EGLint format, E
|
||||
|
||||
#endif
|
||||
|
||||
void EglImageFactory::freeEGLImages(EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) {
|
||||
Q_UNUSED(dpy);
|
||||
Q_UNUSED(images);
|
||||
|
||||
// When the cache is disabled, we just insert one element at a time
|
||||
// with key of nullptr and clear it after every frame.
|
||||
if (m_CacheDisabled) {
|
||||
m_CachedImages.clear();
|
||||
}
|
||||
void EglImageFactory::freeEGLImages() {
|
||||
SDL_assert(m_LastImageCtx.has_value());
|
||||
m_LastImageCtx.reset();
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef HAVE_LIBVA
|
||||
#include <va/va_drmcommon.h>
|
||||
#endif
|
||||
|
||||
#include <optional>
|
||||
|
||||
class EglImageFactory
|
||||
{
|
||||
class EglImageContext {
|
||||
@@ -64,19 +64,14 @@ public:
|
||||
ssize_t exportVAImages(AVFrame* frame, uint32_t exportFlags, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]);
|
||||
#endif
|
||||
|
||||
void freeEGLImages();
|
||||
|
||||
bool supportsImportingFormat(EGLDisplay dpy, EGLint format);
|
||||
bool supportsImportingModifier(EGLDisplay dpy, EGLint format, EGLuint64KHR modifier);
|
||||
|
||||
void freeEGLImages(EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]);
|
||||
|
||||
private:
|
||||
ssize_t queryImageCache(AVFrame* frame, EGLImage images[EGL_MAX_PLANES]);
|
||||
void populateImageCache(AVFrame* frame, EglImageContext &&imgCtx);
|
||||
|
||||
private:
|
||||
IFFmpegRenderer* m_Renderer;
|
||||
bool m_CacheDisabled;
|
||||
std::unordered_map<AVBuffer*, EglImageContext> m_CachedImages;
|
||||
std::optional<EglImageContext> m_LastImageCtx;
|
||||
bool m_EGLExtDmaBuf;
|
||||
PFNEGLCREATEIMAGEPROC m_eglCreateImage;
|
||||
PFNEGLDESTROYIMAGEPROC m_eglDestroyImage;
|
||||
|
||||
@@ -874,7 +874,7 @@ void EGLRenderer::renderFrame(AVFrame* frame)
|
||||
}
|
||||
}
|
||||
|
||||
m_Backend->freeEGLImages(m_EGLDisplay, imgs);
|
||||
m_Backend->freeEGLImages();
|
||||
|
||||
// Free the DMA-BUF backing the last frame now that it is definitely
|
||||
// no longer being used anymore. While the PRIME FD stays around until
|
||||
@@ -899,6 +899,6 @@ bool EGLRenderer::testRenderFrame(AVFrame* frame)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Backend->freeEGLImages(m_EGLDisplay, imgs);
|
||||
m_Backend->freeEGLImages();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ public:
|
||||
}
|
||||
|
||||
// Free the resources allocated during the last `exportEGLImages` call
|
||||
virtual void freeEGLImages(EGLDisplay, EGLImage[EGL_MAX_PLANES]) {}
|
||||
virtual void freeEGLImages() {}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DRM
|
||||
|
||||
@@ -1162,8 +1162,8 @@ VAAPIRenderer::exportEGLImages(AVFrame *frame, EGLDisplay dpy,
|
||||
}
|
||||
|
||||
void
|
||||
VAAPIRenderer::freeEGLImages(EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) {
|
||||
m_EglImageFactory.freeEGLImages(dpy, images);
|
||||
VAAPIRenderer::freeEGLImages() {
|
||||
m_EglImageFactory.freeEGLImages();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
virtual AVPixelFormat getEGLImagePixelFormat() override;
|
||||
virtual bool initializeEGL(EGLDisplay dpy, const EGLExtensions &ext) override;
|
||||
virtual ssize_t exportEGLImages(AVFrame *frame, EGLDisplay dpy, EGLImage images[EGL_MAX_PLANES]) override;
|
||||
virtual void freeEGLImages(EGLDisplay dpy, EGLImage[EGL_MAX_PLANES]) override;
|
||||
virtual void freeEGLImages() override;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DRM
|
||||
|
||||
Reference in New Issue
Block a user