--- a/app/streaming/video/ffmpeg-renderers/eglvid.h +++ b/app/streaming/video/ffmpeg-renderers/eglvid.h @@ -57,6 +57,8 @@ int m_GlesMajorVersion; int m_GlesMinorVersion; bool m_HasExtUnpackSubimage; + bool m_VdiNearestOneToOne; + int m_VdiTextureFilter; #define NV12_PARAM_YUVMAT 0 #define NV12_PARAM_OFFSET 1 --- a/app/streaming/video/ffmpeg-renderers/eglvid.cpp +++ b/app/streaming/video/ffmpeg-renderers/eglvid.cpp @@ -75,7 +75,9 @@ m_eglClientWaitSync(nullptr), m_GlesMajorVersion(0), m_GlesMinorVersion(0), - m_HasExtUnpackSubimage(false) + m_HasExtUnpackSubimage(false), + m_VdiNearestOneToOne(qEnvironmentVariableIntValue("VDI_EGL_NEAREST_1TO1") == 1), + m_VdiTextureFilter(GL_LINEAR) { SDL_assert(backendRenderer); SDL_assert(backendRenderer->canExportEGL()); @@ -812,6 +814,24 @@ dst.w = drawableWidth; dst.h = drawableHeight; StreamUtils::scaleSourceToDestinationSurface(&src, &dst); + + // At exact pixel size no resampling is needed. Keep linear filtering for + // scaled video and all other backends. Never change overlay filtering. + if (m_VdiNearestOneToOne && m_EGLImagePixelFormat == AV_PIX_FMT_DRM_PRIME) { + const int filter = dst.w == frame->width && dst.h == frame->height ? GL_NEAREST : GL_LINEAR; + if (filter != m_VdiTextureFilter) { + for (ssize_t i = 0; i < plane_count; ++i) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_Textures[i]); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, filter); + } + m_VdiTextureFilter = filter; + EGL_LOG(Info, "VDI video texture filter: %s (%dx%d -> %dx%d)", + filter == GL_NEAREST ? "nearest" : "linear", + frame->width, frame->height, dst.w, dst.h); + } + } glViewport(dst.x, dst.y, dst.w, dst.h); glUseProgram(m_ShaderProgram);