add support for nvenc and accel_assist
This commit is contained in:
@@ -63,3 +63,4 @@ xrdp/xrdp.ini
|
||||
xrdp_configure_options.h
|
||||
xrdpapi/xrdp-xrdpapi-simple
|
||||
.vscode/*
|
||||
xrdp_accel_assist/xrdp-accel-assist
|
||||
|
||||
+8
-1
@@ -44,6 +44,12 @@ else
|
||||
ULALACADIR =
|
||||
endif
|
||||
|
||||
if XRDP_ACCEL
|
||||
ACCELDIR = xrdp_accel_assist
|
||||
else
|
||||
ACCELDIR =
|
||||
endif
|
||||
|
||||
# This should not be dictionary order but build order
|
||||
SUBDIRS = \
|
||||
third_party \
|
||||
@@ -70,7 +76,8 @@ SUBDIRS = \
|
||||
$(XRDPVRDIR) \
|
||||
$(ULALACADIR) \
|
||||
tests \
|
||||
tools
|
||||
tools \
|
||||
$(ACCELDIR)
|
||||
|
||||
distclean-local:
|
||||
-rm -f xrdp_configure_options.h
|
||||
|
||||
@@ -30,6 +30,10 @@ AM_CPPFLAGS = \
|
||||
-DXRDP_PID_PATH=\"${localstatedir}/run\" \
|
||||
-DXRDP_LOG_PATH=\"${localstatedir}/log\"
|
||||
|
||||
if XRDP_NVENC
|
||||
AM_CPPFLAGS += -DXRDP_NVENC
|
||||
endif
|
||||
|
||||
# -no-suppress is an automake-specific flag which is needed
|
||||
# to prevent us missing compiler errors in some circumstances
|
||||
# (see https://github.com/neutrinolabs/xrdp/pull/1843 )
|
||||
|
||||
@@ -154,6 +154,36 @@ g_init(const char *app_name)
|
||||
|
||||
WSAStartup(2, &wsadata);
|
||||
#endif
|
||||
#if defined(XRDP_NVENC)
|
||||
if (g_strcmp(app_name, "xrdp-sesman") == 0)
|
||||
{
|
||||
/* call cuInit() to initalize the nvidia drivers */
|
||||
/* TODO create an issue on nvidia forums to figure out why we need to
|
||||
* do this */
|
||||
if (g_fork() == 0)
|
||||
{
|
||||
typedef int (*cu_init_proc)(int flags);
|
||||
cu_init_proc cu_init;
|
||||
long lib;
|
||||
char cuda_lib_name[] = "libcuda.so";
|
||||
char cuda_func_name[] = "cuInit";
|
||||
|
||||
lib = g_load_library(cuda_lib_name);
|
||||
if (lib != 0)
|
||||
{
|
||||
cu_init = (cu_init_proc)
|
||||
g_get_proc_address(lib, cuda_func_name);
|
||||
if (cu_init != NULL)
|
||||
{
|
||||
cu_init(0);
|
||||
}
|
||||
}
|
||||
log_end();
|
||||
g_deinit();
|
||||
g_exit(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1530,6 +1560,39 @@ g_sck_send_fd_set(int sck, const void *ptr, unsigned int len,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
g_alloc_shm_map_fd(void **addr, int *fd, size_t size)
|
||||
{
|
||||
int lfd = -1;
|
||||
void *laddr;
|
||||
char name[128];
|
||||
static unsigned int autoinc;
|
||||
|
||||
snprintf(name, 128, "/%8.8X%8.8X", getpid(), autoinc++);
|
||||
lfd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (lfd == -1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
shm_unlink(name);
|
||||
if (ftruncate(lfd, size) == -1)
|
||||
{
|
||||
close(lfd);
|
||||
return 2;
|
||||
}
|
||||
/* map fd to address space */
|
||||
laddr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, lfd, 0);
|
||||
if (laddr == MAP_FAILED)
|
||||
{
|
||||
close(lfd);
|
||||
return 3;
|
||||
}
|
||||
*addr = laddr;
|
||||
*fd = lfd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* returns boolean */
|
||||
int
|
||||
|
||||
@@ -124,6 +124,7 @@ int g_sck_recv_fd_set(int sck, void *ptr, unsigned int len,
|
||||
*/
|
||||
int g_sck_send_fd_set(int sck, const void *ptr, unsigned int len,
|
||||
int fds[], unsigned int fdcount);
|
||||
int g_alloc_shm_map_fd(void **addr, int *fd, size_t size);
|
||||
int g_sck_last_error_would_block(int sck);
|
||||
int g_sck_socket_ok(int sck);
|
||||
/**
|
||||
|
||||
@@ -57,6 +57,8 @@ enum xrdp_source
|
||||
XRDP_SOURCE_SESMAN,
|
||||
XRDP_SOURCE_CHANSRV,
|
||||
XRDP_SOURCE_MOD,
|
||||
XORGXRDP_SOURCE_XORG,
|
||||
XORGXRDP_SOURCE_XRDP,
|
||||
|
||||
XRDP_SOURCE_MAX_COUNT
|
||||
};
|
||||
|
||||
@@ -179,6 +179,15 @@ AC_ARG_ENABLE(openh264, AS_HELP_STRING([--enable-openh264],
|
||||
[Use Cisco OpenH264 library (default: no)]),
|
||||
[], [enable_openh264=no])
|
||||
AM_CONDITIONAL(XRDP_OPENH264, [test x$enable_openh264 = xyes])
|
||||
AC_ARG_ENABLE(nvenc, AS_HELP_STRING([--enable-nvenc],
|
||||
[Use nvenc library (default: no), env vars XRDP_NVENC_CFLAGS and
|
||||
XRDP_NVENC_LIBS should be set if used]),
|
||||
[], [enable_nvenc=no])
|
||||
AM_CONDITIONAL(XRDP_NVENC, [test x$enable_nvenc = xyes])
|
||||
AC_ARG_ENABLE(accel, AS_HELP_STRING([--enable-accel],
|
||||
[Build xrdp_accel_assist (default: no, auto set if --enable-nvenc)]),
|
||||
[], [enable_accel=no])
|
||||
# AM_CONDITIONAL(XRDP_ACCEL, [test x$enable_accel = xyes]) later in this file
|
||||
AC_ARG_ENABLE(painter, AS_HELP_STRING([--disable-painter],
|
||||
[Do not use included painter library (default: no)]),
|
||||
[], [enable_painter=yes])
|
||||
@@ -263,6 +272,9 @@ AC_CHECK_HEADER([security/_pam_types.h],
|
||||
AC_CHECK_HEADER([security/pam_constants.h],
|
||||
[AC_DEFINE([HAVE_PAM_CONSTANTS_H], 1, [Using OpenPAM], [])])
|
||||
|
||||
# shm_open may not be in the C library
|
||||
AC_SEARCH_LIBS([shm_open], [rt])
|
||||
|
||||
# Find imlib2
|
||||
case "$with_imlib2" in
|
||||
'' | no) AC_MSG_NOTICE([imlib2 will not be supported])
|
||||
@@ -499,6 +511,21 @@ AS_IF( [test "x$enable_x264" = "xyes"] , [PKG_CHECK_MODULES(XRDP_X264, x264 >= 0
|
||||
|
||||
AS_IF( [test "x$enable_openh264" = "xyes"] , [PKG_CHECK_MODULES(XRDP_OPENH264, openh264 >= 2.0.0)] )
|
||||
|
||||
if test "x$enable_nvenc" = "xyes"
|
||||
then
|
||||
enable_accel=$enable_nvenc
|
||||
if test ! -z "$XRDP_NVENC_CFLAGS"
|
||||
then
|
||||
AC_SUBST(XRDP_NVENC_CFLAGS, ["$XRDP_NVENC_CFLAGS"])
|
||||
fi
|
||||
if test ! -z "$XRDP_NVENC_LIBS"
|
||||
then
|
||||
AC_SUBST(XRDP_NVENC_LIBS, ["$XRDP_NVENC_LIBS"])
|
||||
fi
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(XRDP_ACCEL, [test x$enable_accel = xyes])
|
||||
|
||||
# checking for TurboJPEG
|
||||
if test "x$enable_tjpeg" = "xyes"
|
||||
then
|
||||
@@ -665,6 +692,8 @@ AC_CONFIG_FILES([
|
||||
xup/Makefile
|
||||
third_party/Makefile
|
||||
third_party/tomlc99/Makefile
|
||||
xrdp_accel_assist/Makefile
|
||||
|
||||
])
|
||||
|
||||
AC_REQUIRE_AUX_FILE([tap-driver.sh])
|
||||
@@ -681,6 +710,8 @@ echo " turbo jpeg $enable_tjpeg"
|
||||
echo " rfxcodec $enable_rfxcodec"
|
||||
echo " x264 $enable_x264"
|
||||
echo " openh264 $enable_openh264"
|
||||
echo " nvenc $enable_nvenc"
|
||||
echo " accel $enable_accel"
|
||||
echo " painter $enable_painter"
|
||||
echo " pixman $enable_pixman"
|
||||
echo " fuse $enable_fuse"
|
||||
|
||||
@@ -147,6 +147,7 @@ param=Xorg
|
||||
; Leave the rest parameters as-is unless you understand what will happen.
|
||||
param=-config
|
||||
param=xrdp/xorg.conf
|
||||
;param=xrdp/xorg_nvidia.conf
|
||||
param=-noreset
|
||||
param=-nolisten
|
||||
param=tcp
|
||||
@@ -219,3 +220,4 @@ EnableSyslog=true
|
||||
|
||||
[SessionVariables]
|
||||
PULSE_SCRIPT=@sesmansysconfdir@/pulse/default.pa
|
||||
;XRDP_USE_ACCEL_ASSIST=1
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
EXTRA_DIST = xrdp_accel_assist_shaders.c
|
||||
|
||||
XRDP_EXTRA_LIBS =
|
||||
XRDP_EXTRA_SOURCES =
|
||||
|
||||
if XRDP_NVENC
|
||||
AM_CPPFLAGS += -DXRDP_NVENC
|
||||
AM_CPPFLAGS += $(XRDP_NVENC_CFLAGS)
|
||||
XRDP_EXTRA_LIBS += $(XRDP_NVENC_LIBS)
|
||||
XRDP_EXTRA_SOURCES += xrdp_accel_assist_nvenc.c xrdp_accel_assist_nvenc.h encoder_headers/nvEncodeAPI_11_1.h
|
||||
endif
|
||||
|
||||
pkglibexec_PROGRAMS = \
|
||||
xrdp-accel-assist
|
||||
|
||||
xrdp_accel_assist_SOURCES = \
|
||||
xrdp_accel_assist.c \
|
||||
xrdp_accel_assist.h \
|
||||
xrdp_accel_assist_x11.c \
|
||||
xrdp_accel_assist_x11.h \
|
||||
xrdp_accel_assist_egl.c \
|
||||
xrdp_accel_assist_egl.h \
|
||||
xrdp_accel_assist_glx.c \
|
||||
xrdp_accel_assist_glx.h \
|
||||
$(XRDP_EXTRA_SOURCES)
|
||||
|
||||
xrdp_accel_assist_LDADD = \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
$(XRDP_EXTRA_LIBS) \
|
||||
-lX11 -lepoxy
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2020-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _XRDP_ACCEL_ASSIST_H
|
||||
#define _XRDP_ACCEL_ASSIST_H
|
||||
|
||||
#define XH_YUV420 1
|
||||
#define XH_YUV422 2
|
||||
#define XH_YUV444 3
|
||||
|
||||
#define XH_BT601 0
|
||||
#define XH_BT709FR 1
|
||||
#define XH_BTRFX 2
|
||||
|
||||
struct xh_rect
|
||||
{
|
||||
short x;
|
||||
short y;
|
||||
short w;
|
||||
short h;
|
||||
};
|
||||
|
||||
#define XH_ENC_FLAGS_FORCEIDR (1 << 0)
|
||||
|
||||
enum encoder_result
|
||||
{
|
||||
INCREMENTAL_FRAME_ENCODED, /* P frame */
|
||||
KEY_FRAME_ENCODED, /* IDR frame */
|
||||
ENCODER_ERROR
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "xrdp_accel_assist.h"
|
||||
#include "xrdp_accel_assist_x11.h"
|
||||
#include "xrdp_accel_assist_egl.h"
|
||||
#include "log.h"
|
||||
|
||||
EGLDisplay g_egl_display;
|
||||
EGLContext g_egl_context;
|
||||
static EGLSurface g_egl_surface;
|
||||
static EGLConfig g_ecfg;
|
||||
static EGLint g_num_config;
|
||||
|
||||
/* X11 */
|
||||
extern Display *g_display; /* in xrdp_accel_assist_x11.c */
|
||||
extern Window g_root_window; /* in xrdp_accel_assist_x11.c */
|
||||
|
||||
static EGLint g_choose_config_attr[] =
|
||||
{
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
static EGLint g_create_context_attr[] =
|
||||
{
|
||||
EGL_CONTEXT_MAJOR_VERSION, 3,
|
||||
EGL_CONTEXT_MINOR_VERSION, 3,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
static const EGLint g_create_surface_attr[] =
|
||||
{
|
||||
EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
|
||||
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
static EGLBoolean
|
||||
xrdp_accel_assist_check_ext(const char *ext_name)
|
||||
{
|
||||
if (!epoxy_has_egl_extension(g_egl_display, ext_name))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "%s not present", ext_name);
|
||||
return EGL_FALSE;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "%s present", ext_name);
|
||||
return EGL_TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_init(void)
|
||||
{
|
||||
int egl_ver;
|
||||
int ok;
|
||||
|
||||
ok = eglBindAPI(EGL_OPENGL_API);
|
||||
LOG(LOG_LEVEL_INFO, "eglBindAPI ok %d", ok);
|
||||
g_egl_display = eglGetDisplay((EGLNativeDisplayType) g_display);
|
||||
LOG(LOG_LEVEL_INFO, "g_egl_display %p", g_egl_display);
|
||||
eglInitialize(g_egl_display, NULL, NULL);
|
||||
egl_ver = epoxy_egl_version(g_egl_display);
|
||||
LOG(LOG_LEVEL_INFO, "egl_ver %d", egl_ver);
|
||||
if (egl_ver < 11) /* EGL version 1.1 */
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "egl_ver too old %d", egl_ver);
|
||||
eglTerminate(g_egl_display);
|
||||
return 1;
|
||||
}
|
||||
if ((!xrdp_accel_assist_check_ext("EGL_NOK_texture_from_pixmap")) ||
|
||||
(!xrdp_accel_assist_check_ext("EGL_MESA_image_dma_buf_export")) ||
|
||||
(!xrdp_accel_assist_check_ext("EGL_KHR_image_base")))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "missing ext");
|
||||
eglTerminate(g_egl_display);
|
||||
return 1;
|
||||
}
|
||||
eglChooseConfig(g_egl_display, g_choose_config_attr, &g_ecfg,
|
||||
1, &g_num_config);
|
||||
LOG(LOG_LEVEL_INFO, "g_ecfg %p g_num_config %d", g_ecfg, g_num_config);
|
||||
g_egl_surface = eglCreateWindowSurface(g_egl_display, g_ecfg,
|
||||
g_root_window, NULL);
|
||||
LOG(LOG_LEVEL_INFO, "g_egl_surface %p", g_egl_surface);
|
||||
g_egl_context = eglCreateContext(g_egl_display, g_ecfg,
|
||||
EGL_NO_CONTEXT, g_create_context_attr);
|
||||
LOG(LOG_LEVEL_INFO, "g_egl_context %p", g_egl_context);
|
||||
ok = eglMakeCurrent(g_egl_display, g_egl_surface, g_egl_surface,
|
||||
g_egl_context);
|
||||
LOG(LOG_LEVEL_INFO, "eglMakeCurrent ok %d", ok);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_create_image(Pixmap pixmap, inf_image_t *inf_image)
|
||||
{
|
||||
*inf_image = (inf_image_t)eglCreatePixmapSurface(g_egl_display,
|
||||
g_ecfg, pixmap, g_create_surface_attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_destroy_image(inf_image_t inf_image)
|
||||
{
|
||||
eglDestroySurface(g_egl_display, (EGLSurface)inf_image);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_bind_tex_image(inf_image_t inf_image)
|
||||
{
|
||||
eglBindTexImage(g_egl_display, (EGLSurface)inf_image, EGL_BACK_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_release_tex_image(inf_image_t inf_image)
|
||||
{
|
||||
eglReleaseTexImage(g_egl_display, (EGLSurface)inf_image, EGL_BACK_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _XRDP_ACCEL_ASSIST_EGL_H
|
||||
#define _XRDP_ACCEL_ASSIST_EGL_H
|
||||
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_init(void);
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_create_image(Pixmap pixmap, inf_image_t *inf_image);
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_destroy_image(inf_image_t inf_image);
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_bind_tex_image(inf_image_t inf_image);
|
||||
int
|
||||
xrdp_accel_assist_inf_egl_release_tex_image(inf_image_t inf_image);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/glx.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "xrdp_accel_assist.h"
|
||||
#include "xrdp_accel_assist_x11.h"
|
||||
#include "xrdp_accel_assist_glx.h"
|
||||
#include "log.h"
|
||||
|
||||
static int g_n_fbconfigs = 0;
|
||||
static int g_n_pixconfigs = 0;
|
||||
static GLXFBConfig *g_fbconfigs = NULL;
|
||||
static GLXFBConfig *g_pixconfigs = NULL;
|
||||
static GLXContext g_gl_context = 0;
|
||||
|
||||
/* X11 */
|
||||
extern Display *g_display; /* in xrdp_accel_assist_x11.c */
|
||||
extern Window g_root_window; /* in xrdp_accel_assist_x11.c */
|
||||
extern int g_screen_num; /* in xrdp_accel_assist_x11.c */
|
||||
|
||||
static const int g_fbconfig_attrs[] =
|
||||
{
|
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||
GLX_DOUBLEBUFFER, True,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
None
|
||||
};
|
||||
|
||||
static const int g_pixconfig_attrs[] =
|
||||
{
|
||||
GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
|
||||
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
|
||||
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
|
||||
GLX_DOUBLEBUFFER, False,
|
||||
GLX_Y_INVERTED_EXT, True,
|
||||
None
|
||||
};
|
||||
|
||||
static const int g_pixmap_attribs[] =
|
||||
{
|
||||
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
|
||||
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
|
||||
None
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_init(void)
|
||||
{
|
||||
const char *ext_str;
|
||||
int glx_ver;
|
||||
int ok;
|
||||
|
||||
glx_ver = epoxy_glx_version(g_display, g_screen_num);
|
||||
LOG(LOG_LEVEL_INFO, "glx_ver %d", glx_ver);
|
||||
if (glx_ver < 11) /* GLX version 1.1 */
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "glx_ver too old %d", glx_ver);
|
||||
return 1;
|
||||
}
|
||||
if (!epoxy_has_glx_extension(g_display, g_screen_num,
|
||||
"GLX_EXT_texture_from_pixmap"))
|
||||
{
|
||||
ext_str = glXQueryExtensionsString(g_display, g_screen_num);
|
||||
LOG(LOG_LEVEL_INFO, "GLX_EXT_texture_from_pixmap not present [%s]",
|
||||
ext_str);
|
||||
return 1;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "GLX_EXT_texture_from_pixmap present");
|
||||
g_fbconfigs = glXChooseFBConfig(g_display, g_screen_num,
|
||||
g_fbconfig_attrs, &g_n_fbconfigs);
|
||||
LOG(LOG_LEVEL_INFO, "g_fbconfigs %p", g_fbconfigs);
|
||||
g_gl_context = glXCreateNewContext(g_display, g_fbconfigs[0],
|
||||
GLX_RGBA_TYPE, NULL, 1);
|
||||
LOG(LOG_LEVEL_INFO, "g_gl_context %p", g_gl_context);
|
||||
ok = glXMakeCurrent(g_display, g_root_window, g_gl_context);
|
||||
LOG(LOG_LEVEL_INFO, "ok %d", ok);
|
||||
g_pixconfigs = glXChooseFBConfig(g_display, g_screen_num,
|
||||
g_pixconfig_attrs, &g_n_pixconfigs);
|
||||
LOG(LOG_LEVEL_INFO, "g_pixconfigs %p g_n_pixconfigs %d",
|
||||
g_pixconfigs, g_n_pixconfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_create_image(Pixmap pixmap, inf_image_t *inf_image)
|
||||
{
|
||||
*inf_image = (inf_image_t)glXCreatePixmap(g_display, g_pixconfigs[0],
|
||||
pixmap, g_pixmap_attribs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_destroy_image(inf_image_t inf_image)
|
||||
{
|
||||
glXDestroyPixmap(g_display, (GLXPixmap)inf_image);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_bind_tex_image(inf_image_t inf_image)
|
||||
{
|
||||
glXBindTexImageEXT(g_display, (GLXPixmap)inf_image, GLX_FRONT_EXT, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_release_tex_image(inf_image_t inf_image)
|
||||
{
|
||||
glXReleaseTexImageEXT(g_display, (GLXPixmap)inf_image, GLX_FRONT_EXT);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _XRDP_ACCEL_ASSIST_GLX_H
|
||||
#define _XRDP_ACCEL_ASSIST_GLX_H
|
||||
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_init(void);
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_create_image(Pixmap pixmap, inf_image_t *inf_image);
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_destroy_image(inf_image_t inf_image);
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_bind_tex_image(inf_image_t inf_image);
|
||||
int
|
||||
xrdp_accel_assist_inf_glx_release_tex_image(inf_image_t inf_image);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,383 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "string_calls.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include "encoder_headers/nvEncodeAPI_11_1.h"
|
||||
|
||||
#include "arch.h"
|
||||
#include "os_calls.h"
|
||||
#include "xrdp_accel_assist.h"
|
||||
#include "xrdp_accel_assist_x11.h"
|
||||
#include "xrdp_accel_assist_nvenc.h"
|
||||
#include "log.h"
|
||||
|
||||
#define XH_NVENV_DEFAULT_QP 28
|
||||
|
||||
typedef NVENCSTATUS
|
||||
(NVENCAPI *NvEncodeAPICreateInstanceProc)
|
||||
(NV_ENCODE_API_FUNCTION_LIST *functionList);
|
||||
|
||||
static char g_lib_name[] = "libnvidia-encode.so";
|
||||
static char g_lib_name1[] = "libnvidia-encode.so.1";
|
||||
static char g_func_name[] = "NvEncodeAPICreateInstance";
|
||||
|
||||
static NvEncodeAPICreateInstanceProc g_NvEncodeAPICreateInstance = NULL;
|
||||
|
||||
static NV_ENCODE_API_FUNCTION_LIST g_enc_funcs;
|
||||
|
||||
static long g_lib = 0;
|
||||
|
||||
struct enc_info
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int frameCount;
|
||||
int pad0;
|
||||
void *enc;
|
||||
NV_ENC_OUTPUT_PTR bitstreamBuffer;
|
||||
NV_ENC_INPUT_PTR mappedResource;
|
||||
NV_ENC_BUFFER_FORMAT mappedBufferFmt;
|
||||
NV_ENC_REGISTERED_PTR registeredResource;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_nvenc_init(void)
|
||||
{
|
||||
NVENCSTATUS nv_error;
|
||||
|
||||
g_lib = g_load_library(g_lib_name);
|
||||
if (g_lib == 0)
|
||||
{
|
||||
g_lib = g_load_library(g_lib_name1);
|
||||
if (g_lib == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "load library for %s/%s failed", g_lib_name, g_lib_name1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
g_NvEncodeAPICreateInstance = g_get_proc_address(g_lib, g_func_name);
|
||||
if (g_NvEncodeAPICreateInstance == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "get proc address for %s failed", g_func_name);
|
||||
return 1;
|
||||
}
|
||||
g_memset(&g_enc_funcs, 0, sizeof(g_enc_funcs));
|
||||
g_enc_funcs.version = NV_ENCODE_API_FUNCTION_LIST_VER;
|
||||
nv_error = g_NvEncodeAPICreateInstance(&g_enc_funcs);
|
||||
LOG(LOG_LEVEL_INFO, "NvEncodeAPICreateInstance rv %d", nv_error);
|
||||
if (nv_error != NV_ENC_SUCCESS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_nvenc_create_encoder(int width, int height, int tex,
|
||||
int tex_format, struct enc_info **ei)
|
||||
{
|
||||
NV_ENC_CREATE_BITSTREAM_BUFFER bitstreamParams;
|
||||
NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params;
|
||||
NV_ENC_INITIALIZE_PARAMS createEncodeParams;
|
||||
NV_ENC_MAP_INPUT_RESOURCE mapInputResource;
|
||||
NV_ENC_INPUT_RESOURCE_OPENGL_TEX res;
|
||||
NV_ENC_REGISTER_RESOURCE reg_res;
|
||||
NV_ENC_CONFIG encCfg;
|
||||
NVENCSTATUS nv_error;
|
||||
struct enc_info *lei;
|
||||
char *rateControlMode_str;
|
||||
char *averageBitRate_str;
|
||||
char *qp_str;
|
||||
int qp_int;
|
||||
int averageBitRate_int;
|
||||
int rc_set;
|
||||
|
||||
lei = g_new0(struct enc_info, 1);
|
||||
if (lei == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_memset(¶ms, 0, sizeof(params));
|
||||
params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
|
||||
params.deviceType = NV_ENC_DEVICE_TYPE_OPENGL;
|
||||
params.apiVersion = NVENCAPI_VERSION;
|
||||
nv_error = g_enc_funcs.nvEncOpenEncodeSessionEx(¶ms, &(lei->enc));
|
||||
LOG(LOG_LEVEL_INFO, "nvEncOpenEncodeSessionEx rv %d enc %p", nv_error, lei->enc);
|
||||
if (nv_error != NV_ENC_SUCCESS)
|
||||
{
|
||||
g_free(lei);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_memset(&encCfg, 0, sizeof(encCfg));
|
||||
encCfg.version = NV_ENC_CONFIG_VER;
|
||||
encCfg.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
|
||||
encCfg.gopLength = NVENC_INFINITE_GOPLENGTH;
|
||||
encCfg.frameIntervalP = 1; /* 1 + B_Frame_Count */
|
||||
encCfg.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
|
||||
encCfg.mvPrecision = NV_ENC_MV_PRECISION_QUARTER_PEL;
|
||||
|
||||
/* these env vars can be added / changed in sesman.ini SessionVariables
|
||||
example
|
||||
XRDP_NVENC_RATE_CONTROL_MODE=NV_ENC_PARAMS_RC_CONSTQP
|
||||
XRDP_NVENC_QP=30
|
||||
or
|
||||
XRDP_NVENC_RATE_CONTROL_MODE=NV_ENC_PARAMS_RC_VBR
|
||||
XRDP_NVENC_AVERAGE_BITRATE=2000000 */
|
||||
rateControlMode_str = g_getenv("XRDP_NVENC_RATE_CONTROL_MODE");
|
||||
averageBitRate_str = g_getenv("XRDP_NVENC_AVERAGE_BITRATE");
|
||||
qp_str = g_getenv("XRDP_NVENC_QP");
|
||||
rc_set = 0;
|
||||
if (rateControlMode_str != NULL)
|
||||
{
|
||||
if (g_strcmp(rateControlMode_str, "NV_ENC_PARAMS_RC_CONSTQP") == 0)
|
||||
{
|
||||
if (qp_str != NULL)
|
||||
{
|
||||
qp_int = g_atoi(qp_str);
|
||||
if ((qp_int >= 0) && (qp_int <= 51))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"using NV_ENC_PARAMS_RC_CONSTQP qp %d",
|
||||
qp_int);
|
||||
encCfg.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
|
||||
encCfg.rcParams.constQP.qpInterP = qp_int;
|
||||
encCfg.rcParams.constQP.qpInterB = qp_int;
|
||||
encCfg.rcParams.constQP.qpIntra = qp_int;
|
||||
rc_set = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (g_strcmp(rateControlMode_str, "NV_ENC_PARAMS_RC_VBR") == 0)
|
||||
{
|
||||
if (averageBitRate_str != NULL)
|
||||
{
|
||||
averageBitRate_int = g_atoi(averageBitRate_str);
|
||||
if ((averageBitRate_int >= 5000) &&
|
||||
(averageBitRate_int <= 1000000000))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"using NV_ENC_PARAMS_RC_VBR averageBitRate %d",
|
||||
averageBitRate_int);
|
||||
encCfg.rcParams.rateControlMode = NV_ENC_PARAMS_RC_VBR;
|
||||
encCfg.rcParams.averageBitRate = averageBitRate_int;
|
||||
rc_set = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rc_set)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"using default NV_ENC_PARAMS_RC_CONSTQP qp %d",
|
||||
XH_NVENV_DEFAULT_QP);
|
||||
encCfg.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
|
||||
encCfg.rcParams.constQP.qpInterP = XH_NVENV_DEFAULT_QP;
|
||||
encCfg.rcParams.constQP.qpInterB = XH_NVENV_DEFAULT_QP;
|
||||
encCfg.rcParams.constQP.qpIntra = XH_NVENV_DEFAULT_QP;
|
||||
rc_set = 1;
|
||||
}
|
||||
|
||||
encCfg.encodeCodecConfig.h264Config.chromaFormatIDC = 1;
|
||||
encCfg.encodeCodecConfig.h264Config.idrPeriod = NVENC_INFINITE_GOPLENGTH;
|
||||
encCfg.encodeCodecConfig.h264Config.repeatSPSPPS = 1;
|
||||
encCfg.encodeCodecConfig.h264Config.disableSPSPPS = 0;
|
||||
|
||||
g_memset(&createEncodeParams, 0, sizeof(createEncodeParams));
|
||||
createEncodeParams.version = NV_ENC_INITIALIZE_PARAMS_VER;
|
||||
createEncodeParams.encodeGUID = NV_ENC_CODEC_H264_GUID;
|
||||
createEncodeParams.encodeWidth = width;
|
||||
createEncodeParams.encodeHeight = height;
|
||||
createEncodeParams.darWidth = width;
|
||||
createEncodeParams.darHeight = height;
|
||||
createEncodeParams.frameRateNum = 30;
|
||||
createEncodeParams.frameRateDen = 1;
|
||||
createEncodeParams.enablePTD = 1;
|
||||
createEncodeParams.encodeConfig = &encCfg;
|
||||
nv_error = g_enc_funcs.nvEncInitializeEncoder(lei->enc,
|
||||
&createEncodeParams);
|
||||
LOG(LOG_LEVEL_INFO, "nvEncInitializeEncoder rv %d", nv_error);
|
||||
if (nv_error != NV_ENC_SUCCESS)
|
||||
{
|
||||
g_free(lei);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_memset(&res, 0, sizeof(res));
|
||||
res.texture = tex;
|
||||
res.target = GL_TEXTURE_2D;
|
||||
|
||||
g_memset(®_res, 0, sizeof(reg_res));
|
||||
reg_res.version = NV_ENC_REGISTER_RESOURCE_VER;
|
||||
reg_res.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX;
|
||||
reg_res.width = width;
|
||||
reg_res.height = height;
|
||||
if (tex_format == XH_YUV420)
|
||||
{
|
||||
reg_res.pitch = width;
|
||||
reg_res.bufferFormat = NV_ENC_BUFFER_FORMAT_NV12;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_res.pitch = width * 4;
|
||||
reg_res.bufferFormat = NV_ENC_BUFFER_FORMAT_AYUV;
|
||||
}
|
||||
reg_res.resourceToRegister = &res;
|
||||
reg_res.bufferUsage = NV_ENC_INPUT_IMAGE;
|
||||
nv_error = g_enc_funcs.nvEncRegisterResource(lei->enc, ®_res);
|
||||
LOG(LOG_LEVEL_INFO, "nvEncRegisterResource rv %d", nv_error);
|
||||
if (nv_error != NV_ENC_SUCCESS)
|
||||
{
|
||||
g_free(lei);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_memset(&mapInputResource, 0, sizeof(mapInputResource));
|
||||
mapInputResource.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
|
||||
mapInputResource.registeredResource = reg_res.registeredResource;
|
||||
nv_error = g_enc_funcs.nvEncMapInputResource(lei->enc, &mapInputResource);
|
||||
LOG(LOG_LEVEL_INFO, "nvEncMapInputResource rv %d", nv_error);
|
||||
if (nv_error != NV_ENC_SUCCESS)
|
||||
{
|
||||
g_free(lei);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_memset(&bitstreamParams, 0, sizeof(bitstreamParams));
|
||||
bitstreamParams.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
|
||||
nv_error = g_enc_funcs.nvEncCreateBitstreamBuffer(lei->enc,
|
||||
&bitstreamParams);
|
||||
LOG(LOG_LEVEL_INFO, "nvEncCreateBitstreamBuffer rv %d", nv_error);
|
||||
if (nv_error != NV_ENC_SUCCESS)
|
||||
{
|
||||
g_free(lei);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lei->bitstreamBuffer = bitstreamParams.bitstreamBuffer;
|
||||
lei->mappedResource = mapInputResource.mappedResource;
|
||||
lei->mappedBufferFmt = mapInputResource.mappedBufferFmt;
|
||||
lei->registeredResource = reg_res.registeredResource;
|
||||
lei->width = width;
|
||||
lei->height = height;
|
||||
|
||||
*ei = lei;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_nvenc_delete_encoder(struct enc_info *ei)
|
||||
{
|
||||
g_enc_funcs.nvEncUnmapInputResource(ei->enc, ei->mappedResource);
|
||||
g_enc_funcs.nvEncUnregisterResource(ei->enc, ei->registeredResource);
|
||||
g_enc_funcs.nvEncDestroyBitstreamBuffer(ei->enc, ei->bitstreamBuffer);
|
||||
g_enc_funcs.nvEncDestroyEncoder(ei->enc);
|
||||
g_free(ei);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
enum encoder_result
|
||||
xrdp_accel_assist_nvenc_encode(struct enc_info *ei, int tex,
|
||||
void *cdata, int *cdata_bytes,
|
||||
int flags)
|
||||
{
|
||||
NV_ENC_PIC_PARAMS picParams;
|
||||
NV_ENC_LOCK_BITSTREAM lockBitstream;
|
||||
NVENCSTATUS nv_error;
|
||||
enum encoder_result rv;
|
||||
|
||||
/* sync before encoding */
|
||||
glFinish();
|
||||
|
||||
g_memset(&picParams, 0, sizeof(picParams));
|
||||
picParams.version = NV_ENC_PIC_PARAMS_VER;
|
||||
picParams.inputBuffer = ei->mappedResource;
|
||||
picParams.bufferFmt = ei->mappedBufferFmt;
|
||||
picParams.inputWidth = ei->width;
|
||||
picParams.inputHeight = ei->height;
|
||||
picParams.outputBitstream = ei->bitstreamBuffer;
|
||||
picParams.inputTimeStamp = ei->frameCount;
|
||||
picParams.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
|
||||
picParams.encodePicFlags = NV_ENC_PIC_FLAG_OUTPUT_SPSPPS;
|
||||
if ((flags & XH_ENC_FLAGS_FORCEIDR) || (ei->frameCount < 1))
|
||||
{
|
||||
picParams.encodePicFlags |= NV_ENC_PIC_FLAG_FORCEIDR;
|
||||
LOG(LOG_LEVEL_INFO, "Forcing NVENC H264 IDR SPSPPS for frame id: %d",
|
||||
ei->frameCount);
|
||||
}
|
||||
nv_error = g_enc_funcs.nvEncEncodePicture(ei->enc, &picParams);
|
||||
rv = ENCODER_ERROR;
|
||||
if (nv_error == NV_ENC_SUCCESS)
|
||||
{
|
||||
g_memset(&lockBitstream, 0, sizeof(lockBitstream));
|
||||
lockBitstream.version = NV_ENC_LOCK_BITSTREAM_VER;
|
||||
lockBitstream.outputBitstream = ei->bitstreamBuffer;
|
||||
lockBitstream.doNotWait = 0;
|
||||
nv_error = g_enc_funcs.nvEncLockBitstream(ei->enc, &lockBitstream);
|
||||
if (nv_error == NV_ENC_SUCCESS)
|
||||
{
|
||||
if (*cdata_bytes >= ((int) (lockBitstream.bitstreamSizeInBytes)))
|
||||
{
|
||||
g_memcpy(cdata, lockBitstream.bitstreamBufferPtr,
|
||||
lockBitstream.bitstreamSizeInBytes);
|
||||
*cdata_bytes = lockBitstream.bitstreamSizeInBytes;
|
||||
rv = INCREMENTAL_FRAME_ENCODED;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "error not enough room %d %d",
|
||||
*cdata_bytes,
|
||||
(int) (lockBitstream.bitstreamSizeInBytes));
|
||||
}
|
||||
g_enc_funcs.nvEncUnlockBitstream(ei->enc,
|
||||
lockBitstream.outputBitstream);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "error nvEncLockBitstream %d",
|
||||
nv_error);
|
||||
}
|
||||
ei->frameCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "error nvEncEncodePicture %d", nv_error);
|
||||
}
|
||||
if (rv == INCREMENTAL_FRAME_ENCODED
|
||||
&& (picParams.encodePicFlags & NV_ENC_PIC_FLAG_FORCEIDR))
|
||||
{
|
||||
return KEY_FRAME_ENCODED;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _XRDP_ACCEL_ASSIST_NVENC_H
|
||||
#define _XRDP_ACCEL_ASSIST_NVENC_H
|
||||
|
||||
int
|
||||
xrdp_accel_assist_nvenc_init(void);
|
||||
int
|
||||
xrdp_accel_assist_nvenc_create_encoder(int width, int height, int tex,
|
||||
int tex_format, struct enc_info **ei);
|
||||
int
|
||||
xrdp_accel_assist_nvenc_delete_encoder(struct enc_info *ei);
|
||||
enum encoder_result
|
||||
xrdp_accel_assist_nvenc_encode(struct enc_info *ei, int tex,
|
||||
void *cdata, int *cdata_bytes,
|
||||
int flags);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2022-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* GLSL shaders
|
||||
* this file is not compiled directly, it is included in
|
||||
* xrdp_accel_assist_x11.c */
|
||||
|
||||
static const GLchar g_vs[] = "\
|
||||
attribute vec4 position;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
gl_Position = vec4(position.xy, 0.0, 1.0);\n\
|
||||
}\n";
|
||||
|
||||
static const GLchar g_fs_copy[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
gl_FragColor = texture2D(tex, gl_FragCoord.xy / tex_size);\n\
|
||||
}\n";
|
||||
|
||||
static const GLchar g_fs_rgb_to_yuv420[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
uniform vec4 ymath;\n\
|
||||
uniform vec4 umath;\n\
|
||||
uniform vec4 vmath;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
vec4 pix;\n\
|
||||
float x;\n\
|
||||
float y;\n\
|
||||
x = gl_FragCoord.x;\n\
|
||||
y = gl_FragCoord.y;\n\
|
||||
if (y < tex_size.y)\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(ymath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
y = floor(y - tex_size.y) * 2.0 + 0.5;\n\
|
||||
if (mod(x, 2.0) < 1.0)\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix += texture2D(tex, vec2(x + 1.0, y) / tex_size);\n\
|
||||
pix += texture2D(tex, vec2(x, y + 1.0) / tex_size);\n\
|
||||
pix += texture2D(tex, vec2(x + 1.0, y + 1.0) / tex_size);\n\
|
||||
pix /= 4.0;\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(umath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix += texture2D(tex, vec2(x - 1.0, y) / tex_size);\n\
|
||||
pix += texture2D(tex, vec2(x, y + 1.0) / tex_size);\n\
|
||||
pix += texture2D(tex, vec2(x - 1.0, y + 1.0) / tex_size);\n\
|
||||
pix /= 4.0;\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(vmath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n";
|
||||
|
||||
static const GLchar g_fs_rgb_to_yuv422[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
uniform vec4 ymath;\n\
|
||||
uniform vec4 umath;\n\
|
||||
uniform vec4 vmath;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
vec4 pix;\n\
|
||||
vec4 pix1;\n\
|
||||
vec4 pixs;\n\
|
||||
float x;\n\
|
||||
float y;\n\
|
||||
x = gl_FragCoord.x;\n\
|
||||
x = floor(x) * 2.0 + 0.5;\n\
|
||||
y = gl_FragCoord.y;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix1 = texture2D(tex, vec2(x + 1.0, y) / tex_size);\n\
|
||||
pixs = (pix + pix1) / 2.0;\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix1.a = 1.0;\n\
|
||||
pixs.a = 1.0;\n\
|
||||
pix.r = dot(ymath, pix);\n\
|
||||
pix.g = dot(umath, pixs);\n\
|
||||
pix.b = dot(ymath, pix1);\n\
|
||||
pix.a = dot(vmath, pixs);\n\
|
||||
gl_FragColor = clamp(pix, 0.0, 1.0);\n\
|
||||
}\n";
|
||||
|
||||
static const GLchar g_fs_rgb_to_yuv444[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
uniform vec4 ymath;\n\
|
||||
uniform vec4 umath;\n\
|
||||
uniform vec4 vmath;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
vec4 pix;\n\
|
||||
pix = texture2D(tex, gl_FragCoord.xy / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(dot(vmath, pix), dot(umath, pix), dot(ymath, pix), 1.0);\n\
|
||||
gl_FragColor = clamp(pix, 0.0, 1.0);\n\
|
||||
}\n";
|
||||
|
||||
/*
|
||||
RGB
|
||||
00 10 20 30 40 50 60 70 80 90 A0 B0 C0 D0 E0 F0
|
||||
01 11 21 31 41 51 61 71 81 91 A1 B1 C1 D1 E1 F1
|
||||
02 12 22 32 42 52 62 72 82 92 A2 B2 C2 D2 E2 F2
|
||||
03 13 23 33 43 53 63 73 83 93 A3 B3 C3 D3 E3 F3
|
||||
04 14 24 34 44 54 64 74 84 94 A4 B4 C4 D4 E4 F4
|
||||
05 15 25 35 45 55 65 75 85 95 A5 B5 C5 D5 E5 F5
|
||||
06 16 26 36 46 56 66 76 86 96 A6 B6 C6 D6 E6 F6
|
||||
07 17 27 37 47 57 67 77 87 97 A7 B7 C7 D7 E7 F7
|
||||
08 18 28 38 48 58 68 78 88 98 A8 B8 C8 D8 E8 F8
|
||||
09 19 29 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9
|
||||
0A 1A 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA
|
||||
0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AB BB CB DB EB FB
|
||||
0C 1C 2C 3C 4C 5C 6C 7C 8C 9C AC BC CC DC EC FC
|
||||
0D 1D 2D 3D 4D 5D 6D 7D 8D 9D AD BD CD DD ED FD
|
||||
0E 1E 2E 3E 4E 5E 6E 7E 8E 9E AE BE CE DE EE FE
|
||||
0F 1F 2F 3F 4F 5F 6F 7F 8F 9F AF BF CF DF EF FF
|
||||
|
||||
MAIN VIEW - NV12
|
||||
|
||||
/---------------------Y-----------------------\
|
||||
00 10 20 30 40 50 60 70 80 90 A0 B0 C0 D0 E0 F0
|
||||
01 11 21 31 41 51 61 71 81 91 A1 B1 C1 D1 E1 F1
|
||||
...
|
||||
0F 1F 2F 3F 4F 5F 6F 7F 8F 9F AF BF CF DF EF FF
|
||||
|
||||
/U /V /U /V /U /V /U /V /U /V /U /V /U /V /U /V
|
||||
00 00 20 20 40 40 60 60 80 80 A0 A0 C0 C0 E0 E0
|
||||
02 02 22 22 42 42 62 62 82 82 A2 A2 C2 C2 E2 E2
|
||||
...
|
||||
0E 0E 2E 2E 4E 4E 6E 6E 8E 8E AE AE CE CE EE EE
|
||||
*/
|
||||
static const GLchar g_fs_rgb_to_yuv420_mv[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
uniform vec4 ymath;\n\
|
||||
uniform vec4 umath;\n\
|
||||
uniform vec4 vmath;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
vec4 pix;\n\
|
||||
float x;\n\
|
||||
float y;\n\
|
||||
x = gl_FragCoord.x;\n\
|
||||
y = gl_FragCoord.y;\n\
|
||||
if (y < tex_size.y)\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(ymath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
y = floor(y - tex_size.y) * 2.0 + 0.5;\n\
|
||||
if (mod(x, 2.0) < 1.0)\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(umath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x - 1.0, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(vmath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n";
|
||||
|
||||
/*
|
||||
AUXILIARY VIEW - NV12
|
||||
|
||||
/---------------------U-----------------------\
|
||||
01 11 21 31 41 51 61 71 81 91 A1 B1 C1 D1 E1 F1
|
||||
03 13 23 33 43 53 63 73 83 93 A3 B3 C3 D3 E3 F4
|
||||
...
|
||||
0F 1F 2F 3F 4F 5F 6F 7F 8F 9F AF BF CF DF EF FF
|
||||
/---------------------V-----------------------\
|
||||
01 11 21 31 41 51 61 71 81 91 A1 B1 C1 D1 E1 F1
|
||||
03 13 23 33 43 53 63 73 83 93 A3 B3 C3 D3 E3 F4
|
||||
...
|
||||
0F 1F 2F 3F 4F 5F 6F 7F 8F 9F AF BF CF DF EF FF
|
||||
... (8 LINES U, 8 LINES V, REPEAT)
|
||||
|
||||
/U /V /U /V /U /V /U /V /U /V /U /V /U /V /U /V
|
||||
10 10 30 30 50 50 70 70 90 90 B0 B0 D0 D0 F0 F0
|
||||
12 12 32 32 52 52 72 72 92 92 B2 B2 D2 D2 F2 F2
|
||||
...
|
||||
1E 1E 3E 3E 5E 5E 7E 7E 9E 9E BE BE DE DE FE FE
|
||||
*/
|
||||
static const GLchar g_fs_rgb_to_yuv420_av[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
uniform vec4 umath;\n\
|
||||
uniform vec4 vmath;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
vec4 pix;\n\
|
||||
float x;\n\
|
||||
float y;\n\
|
||||
float y1;\n\
|
||||
x = gl_FragCoord.x;\n\
|
||||
y = gl_FragCoord.y;\n\
|
||||
if (y < tex_size.y)\n\
|
||||
{\n\
|
||||
y1 = mod(y, 16.0);\n\
|
||||
if (y1 < 8.0)\n\
|
||||
{\n\
|
||||
y = floor(y / 16.0) * 8.0 + y1;\n\
|
||||
y = floor(y) * 2.0 + 1.5;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(umath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
y = floor(y / 16.0) * 8.0 + (y1 - 8.0);\n\
|
||||
y = floor(y) * 2.0 + 1.5;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(vmath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
y = floor(y - tex_size.y) * 2.0 + 0.5;\n\
|
||||
if (mod(x, 2.0) < 1.0)\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x + 1.0, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(umath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(vmath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n";
|
||||
|
||||
/*
|
||||
AUXILIARY VIEW V2 - NV12
|
||||
|
||||
/----------U----------\ /----------V----------\
|
||||
10 30 50 70 90 B0 D0 F0 10 30 50 70 90 B0 D0 F0
|
||||
11 31 51 71 91 B1 D1 F1 11 31 51 71 91 B1 D1 F1
|
||||
...
|
||||
1F 3F 5F 7F 9F BF DF FF 1F 3F 5F 7F 9F BF DF FF
|
||||
|
||||
/----------U----------\ /----------V----------\
|
||||
01 21 41 61 81 A1 C1 E1 01 21 41 61 81 A1 C1 E1
|
||||
03 23 43 63 83 A3 C3 E3 03 23 43 63 83 A3 C3 E3
|
||||
...
|
||||
0F 2F 4F 6F 8F AF CF EF 0F 2F 4F 6F 8F AF CF EF
|
||||
*/
|
||||
static const GLchar g_fs_rgb_to_yuv420_av_v2[] = "\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec2 tex_size;\n\
|
||||
uniform vec4 umath;\n\
|
||||
uniform vec4 vmath;\n\
|
||||
void main(void)\n\
|
||||
{\n\
|
||||
vec4 pix;\n\
|
||||
float x;\n\
|
||||
float y;\n\
|
||||
float x1;\n\
|
||||
x = gl_FragCoord.x;\n\
|
||||
y = gl_FragCoord.y;\n\
|
||||
x1 = tex_size.x / 2.0;\n\
|
||||
if (y < tex_size.y)\n\
|
||||
{\n\
|
||||
if (x < x1)\n\
|
||||
{\n\
|
||||
x = floor(x) * 2.0 + 1.5;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(umath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
x = floor(x - x1) * 2.0 + 1.5;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(vmath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
y = floor(y - tex_size.y) * 2.0 + 1.5;\n\
|
||||
if (x < x1)\n\
|
||||
{\n\
|
||||
x = floor(x) * 2.0 + 0.5;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(umath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
else\n\
|
||||
{\n\
|
||||
x = floor(x - x1) * 2.0 + 0.5;\n\
|
||||
pix = texture2D(tex, vec2(x, y) / tex_size);\n\
|
||||
pix.a = 1.0;\n\
|
||||
pix = vec4(clamp(dot(vmath, pix), 0.0, 1.0), 0.0, 0.0, 1.0);\n\
|
||||
gl_FragColor = pix;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n";
|
||||
@@ -0,0 +1,858 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2020-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Currently nvenc requires GLX because NVidia's EGL does not have
|
||||
* EGL_NOK_texture_from_pixmap extension but NVidia's GLX does have
|
||||
* GLX_EXT_texture_from_pixmap. We require one if those,
|
||||
* also, va required EGL because it used dma bufs.
|
||||
* I do not think any vendor's GLX support dma bufs */
|
||||
/* Things like render on one GPU and encode with another is possible
|
||||
* but not supported now. */
|
||||
/* One suggestion about dma bufs and GLX, one can use the DRI3
|
||||
* extension to get dma buffs for pixmaps */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "xrdp_accel_assist.h"
|
||||
#include "xrdp_accel_assist_x11.h"
|
||||
#include "xrdp_accel_assist_glx.h"
|
||||
#include "xrdp_accel_assist_egl.h"
|
||||
#include "log.h"
|
||||
|
||||
/* set to 1 to dump bmp files into /tmp */
|
||||
#define XR_DUMP_FRAMEBUFFER 0
|
||||
|
||||
/* set to 1 to dump bmp files into /tmp */
|
||||
#define XR_DUMP_PIXMAP 0
|
||||
|
||||
#if defined(XRDP_NVENC)
|
||||
#include "xrdp_accel_assist_nvenc.h"
|
||||
#endif
|
||||
|
||||
/* X11 */
|
||||
Display *g_display = NULL;
|
||||
static int g_x_socket = 0;
|
||||
int g_screen_num = 0;
|
||||
static Screen *g_screen = NULL;
|
||||
Window g_root_window = None;
|
||||
static Visual *g_vis = NULL;
|
||||
static GC g_gc;
|
||||
|
||||
/* encoders: nvenc or va */
|
||||
struct enc_funcs
|
||||
{
|
||||
int (*init)(void);
|
||||
int (*create_enc)(int width, int height, int tex, int tex_format,
|
||||
struct enc_info **ei);
|
||||
int (*destroy_enc)(struct enc_info *ei);
|
||||
enum encoder_result (*encode)(struct enc_info *ei, int tex,
|
||||
void *cdata, int *cdata_bytes,
|
||||
int flags);
|
||||
};
|
||||
|
||||
static struct enc_funcs g_enc_funcs[] =
|
||||
{
|
||||
{
|
||||
NULL, NULL, NULL, NULL
|
||||
},
|
||||
{
|
||||
#if defined(XRDP_NVENC)
|
||||
xrdp_accel_assist_nvenc_init,
|
||||
xrdp_accel_assist_nvenc_create_encoder,
|
||||
xrdp_accel_assist_nvenc_delete_encoder,
|
||||
xrdp_accel_assist_nvenc_encode
|
||||
#else
|
||||
NULL, NULL, NULL, NULL
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/* GL interface: EGL or GLX */
|
||||
struct inf_funcs
|
||||
{
|
||||
int (*init)(void);
|
||||
int (*create_image)(Pixmap pixmap, inf_image_t *inf_image);
|
||||
int (*destroy_image)(inf_image_t inf_image);
|
||||
int (*bind_tex_image)(inf_image_t inf_image);
|
||||
int (*release_tex_image)(inf_image_t inf_image);
|
||||
};
|
||||
|
||||
static struct inf_funcs g_inf_funcs[] =
|
||||
{
|
||||
{
|
||||
xrdp_accel_assist_inf_egl_init,
|
||||
xrdp_accel_assist_inf_egl_create_image,
|
||||
xrdp_accel_assist_inf_egl_destroy_image,
|
||||
xrdp_accel_assist_inf_egl_bind_tex_image,
|
||||
xrdp_accel_assist_inf_egl_release_tex_image
|
||||
},
|
||||
{
|
||||
xrdp_accel_assist_inf_glx_init,
|
||||
xrdp_accel_assist_inf_glx_create_image,
|
||||
xrdp_accel_assist_inf_glx_destroy_image,
|
||||
xrdp_accel_assist_inf_glx_bind_tex_image,
|
||||
xrdp_accel_assist_inf_glx_release_tex_image
|
||||
}
|
||||
};
|
||||
|
||||
/* 0 = EGL, 1 = GLX */
|
||||
/* 0 = va, 1 = nvenc */
|
||||
#define INF_EGL 0
|
||||
#define INF_GLX 1
|
||||
#define ENC_VA 0
|
||||
#define ENC_NVENC 1
|
||||
static int g_inf = INF_EGL;
|
||||
static int g_enc = ENC_VA;
|
||||
|
||||
struct mon_info
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
Pixmap pixmap;
|
||||
inf_image_t inf_image;
|
||||
GLuint bmp_texture;
|
||||
GLuint enc_texture;
|
||||
int tex_format;
|
||||
GLfloat *(*get_vertices)(GLuint *vertices_bytes,
|
||||
GLuint *vertices_pointes,
|
||||
int num_crects, struct xh_rect *crects,
|
||||
int left, int top, int width, int height);
|
||||
struct xh_rect viewport;
|
||||
struct enc_info *ei;
|
||||
};
|
||||
|
||||
#define MAX_MON 16
|
||||
static struct mon_info g_mons[MAX_MON];
|
||||
|
||||
static GLuint g_quad_vao = 0;
|
||||
static GLuint g_fb = 0;
|
||||
|
||||
#define XH_SHADERCOPY 0
|
||||
#define XH_SHADERRGB2YUV420 1
|
||||
#define XH_SHADERRGB2YUV422 2
|
||||
#define XH_SHADERRGB2YUV444 3
|
||||
#define XH_SHADERRGB2YUV420MV 4
|
||||
#define XH_SHADERRGB2YUV420AV 5
|
||||
#define XH_SHADERRGB2YUV420AVV2 6
|
||||
|
||||
#define XH_NUM_SHADERS 7
|
||||
|
||||
struct shader_info
|
||||
{
|
||||
GLuint vertex_shader;
|
||||
GLuint fragment_shader;
|
||||
GLuint program;
|
||||
GLint tex_loc;
|
||||
GLint tex_size_loc;
|
||||
GLint ymath_loc;
|
||||
GLint umath_loc;
|
||||
GLint vmath_loc;
|
||||
int current_matrix;
|
||||
};
|
||||
static struct shader_info g_si[XH_NUM_SHADERS];
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static const GLfloat g_vertices[] =
|
||||
{
|
||||
-1.0f, 1.0f,
|
||||
-1.0f, -1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, -1.0f
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
struct rgb2yuv_matrix
|
||||
{
|
||||
GLfloat ymath[4];
|
||||
GLfloat umath[4];
|
||||
GLfloat vmath[4];
|
||||
};
|
||||
|
||||
static struct rgb2yuv_matrix g_rgb2yux_matrix[3] =
|
||||
{
|
||||
{
|
||||
/* yuv bt601 lagecy */
|
||||
{ 66.0 / 256.0, 129.0 / 256.0, 25.0 / 256.0, 16.0 / 256.0 },
|
||||
{ -38.0 / 256.0, -74.0 / 256.0, 112.0 / 256.0, 128.0 / 256.0 },
|
||||
{ 112.0 / 256.0, -94.0 / 256.0, -18.0 / 256.0, 128.0 / 256.0 }
|
||||
},
|
||||
{
|
||||
/* yuv bt709 full range, used in gfx h264 */
|
||||
{ 54.0 / 256.0, 183.0 / 256.0, 18.0 / 256.0, 0.0 / 256.0 },
|
||||
{ -29.0 / 256.0, -99.0 / 256.0, 128.0 / 256.0, 128.0 / 256.0 },
|
||||
{ 128.0 / 256.0, -116.0 / 256.0, -12.0 / 256.0, 128.0 / 256.0 }
|
||||
},
|
||||
{
|
||||
/* yuv remotefx and gfx progressive remotefx */
|
||||
{ 0.299000, 0.587000, 0.114000, 0.0 },
|
||||
{ -0.168935, -0.331665, 0.500590, 0.5 },
|
||||
{ 0.499830, -0.418531, -0.081282, 0.5 }
|
||||
}
|
||||
};
|
||||
|
||||
#include "xrdp_accel_assist_shaders.c"
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_x11_init(void)
|
||||
{
|
||||
const GLchar *vsource[XH_NUM_SHADERS];
|
||||
const GLchar *fsource[XH_NUM_SHADERS];
|
||||
GLint linked;
|
||||
GLint compiled;
|
||||
GLint vlength;
|
||||
GLint flength;
|
||||
GLuint quad_vbo;
|
||||
int index;
|
||||
int gl_ver;
|
||||
int major_opcode, first_event, first_error;
|
||||
|
||||
/* x11 */
|
||||
g_display = XOpenDisplay(0);
|
||||
if (g_display == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
g_x_socket = XConnectionNumber(g_display);
|
||||
g_screen_num = DefaultScreen(g_display);
|
||||
g_screen = ScreenOfDisplay(g_display, g_screen_num);
|
||||
g_root_window = RootWindowOfScreen(g_screen);
|
||||
g_vis = XDefaultVisual(g_display, g_screen_num);
|
||||
g_gc = DefaultGC(g_display, 0);
|
||||
if (XQueryExtension(g_display, "NV-CONTROL", &major_opcode, &first_event,
|
||||
&first_error))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: "
|
||||
"detected NVIDIA XServer");
|
||||
g_inf = INF_GLX;
|
||||
g_enc = ENC_NVENC;
|
||||
if (g_inf_funcs[g_inf].init() != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_init: "
|
||||
"GLX init failed");
|
||||
return 1;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: using GLX");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_inf = INF_EGL;
|
||||
g_enc = ENC_VA;
|
||||
if (g_inf_funcs[g_inf].init() != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_init: "
|
||||
"EGL init failed");
|
||||
return 1;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: using EGL");
|
||||
}
|
||||
gl_ver = epoxy_gl_version();
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: gl_ver %d", gl_ver);
|
||||
if (gl_ver < 30)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_init: "
|
||||
"gl_ver too old %d", gl_ver);
|
||||
return 1;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "vendor: %s",
|
||||
(const char *) glGetString(GL_VENDOR));
|
||||
LOG(LOG_LEVEL_INFO, "version: %s",
|
||||
(const char *) glGetString(GL_VERSION));
|
||||
/* create vertex array */
|
||||
glGenVertexArrays(1, &g_quad_vao);
|
||||
glBindVertexArray(g_quad_vao);
|
||||
glGenBuffers(1, &quad_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices,
|
||||
GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, NULL);
|
||||
glGenFramebuffers(1, &g_fb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
glDeleteBuffers(1, &quad_vbo);
|
||||
|
||||
/* create copy shader */
|
||||
vsource[XH_SHADERCOPY] = g_vs;
|
||||
fsource[XH_SHADERCOPY] = g_fs_copy;
|
||||
/* create rgb2yuv shader */
|
||||
vsource[XH_SHADERRGB2YUV420] = g_vs;
|
||||
fsource[XH_SHADERRGB2YUV420] = g_fs_rgb_to_yuv420;
|
||||
/* create rgb2yuv shader */
|
||||
vsource[XH_SHADERRGB2YUV422] = g_vs;
|
||||
fsource[XH_SHADERRGB2YUV422] = g_fs_rgb_to_yuv422;
|
||||
/* create rgb2yuv shader */
|
||||
vsource[XH_SHADERRGB2YUV444] = g_vs;
|
||||
fsource[XH_SHADERRGB2YUV444] = g_fs_rgb_to_yuv444;
|
||||
|
||||
vsource[XH_SHADERRGB2YUV420MV] = g_vs;
|
||||
fsource[XH_SHADERRGB2YUV420MV] = g_fs_rgb_to_yuv420_mv;
|
||||
|
||||
vsource[XH_SHADERRGB2YUV420AV] = g_vs;
|
||||
fsource[XH_SHADERRGB2YUV420AV] = g_fs_rgb_to_yuv420_av;
|
||||
|
||||
vsource[XH_SHADERRGB2YUV420AVV2] = g_vs;
|
||||
fsource[XH_SHADERRGB2YUV420AVV2] = g_fs_rgb_to_yuv420_av_v2;
|
||||
|
||||
for (index = 0; index < XH_NUM_SHADERS; index++)
|
||||
{
|
||||
g_si[index].vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||
g_si[index].fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
vlength = g_strlen(vsource[index]);
|
||||
flength = g_strlen(fsource[index]);
|
||||
glShaderSource(g_si[index].vertex_shader, 1,
|
||||
&(vsource[index]), &vlength);
|
||||
glShaderSource(g_si[index].fragment_shader, 1,
|
||||
&(fsource[index]), &flength);
|
||||
glCompileShader(g_si[index].vertex_shader);
|
||||
glGetShaderiv(g_si[index].vertex_shader, GL_COMPILE_STATUS,
|
||||
&compiled);
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: "
|
||||
"vertex_shader compiled %d", compiled);
|
||||
glCompileShader(g_si[index].fragment_shader);
|
||||
glGetShaderiv(g_si[index].fragment_shader, GL_COMPILE_STATUS,
|
||||
&compiled);
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: "
|
||||
"fragment_shader compiled %d", compiled);
|
||||
g_si[index].program = glCreateProgram();
|
||||
glAttachShader(g_si[index].program, g_si[index].vertex_shader);
|
||||
glAttachShader(g_si[index].program, g_si[index].fragment_shader);
|
||||
glLinkProgram(g_si[index].program);
|
||||
glGetProgramiv(g_si[index].program, GL_LINK_STATUS, &linked);
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: linked %d", linked);
|
||||
g_si[index].tex_loc =
|
||||
glGetUniformLocation(g_si[index].program, "tex");
|
||||
g_si[index].tex_size_loc =
|
||||
glGetUniformLocation(g_si[index].program, "tex_size");
|
||||
g_si[index].ymath_loc =
|
||||
glGetUniformLocation(g_si[index].program, "ymath");
|
||||
g_si[index].umath_loc =
|
||||
glGetUniformLocation(g_si[index].program, "umath");
|
||||
g_si[index].vmath_loc =
|
||||
glGetUniformLocation(g_si[index].program, "vmath");
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_init: tex_loc %d "
|
||||
"tex_size_loc %d ymath_loc %d umath_loc %d vmath_loc %d",
|
||||
g_si[index].tex_loc, g_si[index].tex_size_loc,
|
||||
g_si[index].ymath_loc, g_si[index].umath_loc,
|
||||
g_si[index].vmath_loc);
|
||||
/* set default matrix */
|
||||
glUseProgram(g_si[index].program);
|
||||
if (g_si[index].ymath_loc >= 0)
|
||||
{
|
||||
glUniform4fv(g_si[index].ymath_loc, 1, g_rgb2yux_matrix[1].ymath);
|
||||
}
|
||||
if (g_si[index].umath_loc >= 0)
|
||||
{
|
||||
glUniform4fv(g_si[index].umath_loc, 1, g_rgb2yux_matrix[1].umath);
|
||||
}
|
||||
if (g_si[index].vmath_loc >= 0)
|
||||
{
|
||||
glUniform4fv(g_si[index].vmath_loc, 1, g_rgb2yux_matrix[1].vmath);
|
||||
}
|
||||
glUseProgram(0);
|
||||
}
|
||||
g_memset(g_mons, 0, sizeof(g_mons));
|
||||
if (g_enc_funcs[g_enc].init() != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_init: "
|
||||
"encoder init failed");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_x11_get_wait_objs(intptr_t *objs, int *obj_count)
|
||||
{
|
||||
objs[*obj_count] = g_x_socket;
|
||||
(*obj_count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_x11_check_wait_objs(void)
|
||||
{
|
||||
XEvent xevent;
|
||||
|
||||
while (XPending(g_display) > 0)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_check_wait_objs: "
|
||||
"loop");
|
||||
XNextEvent(g_display, &xevent);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_x11_delete_all_pixmaps(void)
|
||||
{
|
||||
int index;
|
||||
struct mon_info *mi;
|
||||
|
||||
for (index = 0; index < MAX_MON; index++)
|
||||
{
|
||||
mi = g_mons + index;
|
||||
if (mi->pixmap != 0)
|
||||
{
|
||||
g_enc_funcs[g_enc].destroy_enc(mi->ei);
|
||||
glDeleteTextures(1, &(mi->bmp_texture));
|
||||
glDeleteTextures(1, &(mi->enc_texture));
|
||||
g_inf_funcs[g_inf].destroy_image(mi->inf_image);
|
||||
XFreePixmap(g_display, mi->pixmap);
|
||||
mi->pixmap = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static GLfloat *
|
||||
get_vertices_all(GLuint *vertices_bytes, GLuint *vertices_pointes,
|
||||
int num_crects, struct xh_rect *crects,
|
||||
int left, int top, int width, int height)
|
||||
{
|
||||
GLfloat *vertices;
|
||||
|
||||
(void)num_crects;
|
||||
(void)crects;
|
||||
(void)width;
|
||||
(void)height;
|
||||
|
||||
vertices = g_new(GLfloat, 12);
|
||||
if (vertices == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
vertices[0] = -1;
|
||||
vertices[1] = 1;
|
||||
vertices[2] = -1;
|
||||
vertices[3] = -1;
|
||||
vertices[4] = 1;
|
||||
vertices[5] = 1;
|
||||
vertices[6] = -1;
|
||||
vertices[7] = -1;
|
||||
vertices[8] = 1;
|
||||
vertices[9] = 1;
|
||||
vertices[10] = 1;
|
||||
vertices[11] = -1;
|
||||
*vertices_bytes = sizeof(GLfloat) * 12;
|
||||
*vertices_pointes = 6;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static GLfloat *
|
||||
get_vertices420(GLuint *vertices_bytes, GLuint *vertices_pointes,
|
||||
int num_crects, struct xh_rect *crects,
|
||||
int left, int top, int width, int height)
|
||||
{
|
||||
GLfloat *vertices;
|
||||
GLfloat *vert;
|
||||
GLfloat x1;
|
||||
GLfloat x2;
|
||||
GLfloat y1;
|
||||
GLfloat y2;
|
||||
int index;
|
||||
GLfloat fwidth;
|
||||
GLfloat fheight;
|
||||
const GLfloat fac13 = 1.0 / 3.0;
|
||||
const GLfloat fac23 = 2.0 / 3.0;
|
||||
const GLfloat fac43 = 4.0 / 3.0;
|
||||
struct xh_rect *crect;
|
||||
|
||||
if (num_crects < 1)
|
||||
{
|
||||
return get_vertices_all(vertices_bytes, vertices_pointes,
|
||||
num_crects, crects, left, top, width, height);
|
||||
}
|
||||
vertices = g_new(GLfloat, num_crects * 24);
|
||||
if (vertices == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
fwidth = width / 2.0;
|
||||
fheight = height / 2.0;
|
||||
for (index = 0; index < num_crects; index++)
|
||||
{
|
||||
crect = crects + index;
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "get_vertices420: "
|
||||
"rect index %d x %d y %d w %d h %d",
|
||||
index, crect->x, crect->y, crect->w, crect->h);
|
||||
x1 = (crect->x - left) / fwidth;
|
||||
y1 = (crect->y - top) / fheight;
|
||||
x2 = ((crect->x - left) + crect->w) / fwidth;
|
||||
y2 = ((crect->y - top) + crect->h) / fheight;
|
||||
vert = vertices + index * 24;
|
||||
/* y box */
|
||||
vert[0] = x1 - 1.0;
|
||||
vert[1] = y1 * fac23 - 1.0;
|
||||
vert[2] = x1 - 1.0;
|
||||
vert[3] = y2 * fac23 - 1.0;
|
||||
vert[4] = x2 - 1.0;
|
||||
vert[5] = y1 * fac23 - 1.0;
|
||||
vert[6] = x1 - 1.0;
|
||||
vert[7] = y2 * fac23 - 1.0;
|
||||
vert[8] = x2 - 1.0;
|
||||
vert[9] = y1 * fac23 - 1.0;
|
||||
vert[10] = x2 - 1.0;
|
||||
vert[11] = y2 * fac23 - 1.0;
|
||||
/* uv box */
|
||||
vert[12] = x1 - 1.0;
|
||||
vert[13] = (y1 * fac13 + fac43) - 1.0;
|
||||
vert[14] = x1 - 1.0;
|
||||
vert[15] = (y2 * fac13 + fac43) - 1.0;
|
||||
vert[16] = x2 - 1.0;
|
||||
vert[17] = (y1 * fac13 + fac43) - 1.0;
|
||||
vert[18] = x1 - 1.0;
|
||||
vert[19] = (y2 * fac13 + fac43) - 1.0;
|
||||
vert[20] = x2 - 1.0;
|
||||
vert[21] = (y1 * fac13 + fac43) - 1.0;
|
||||
vert[22] = x2 - 1.0;
|
||||
vert[23] = (y2 * fac13 + fac43) - 1.0;
|
||||
}
|
||||
*vertices_bytes = sizeof(GLfloat) * num_crects * 24;
|
||||
*vertices_pointes = num_crects * 12;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static GLfloat *
|
||||
get_vertices444(GLuint *vertices_bytes, GLuint *vertices_pointes,
|
||||
int num_crects, struct xh_rect *crects,
|
||||
int left, int top, int width, int height)
|
||||
{
|
||||
GLfloat *vertices;
|
||||
GLfloat *vert;
|
||||
GLfloat x1;
|
||||
GLfloat x2;
|
||||
GLfloat y1;
|
||||
GLfloat y2;
|
||||
int index;
|
||||
GLfloat fwidth;
|
||||
GLfloat fheight;
|
||||
struct xh_rect *crect;
|
||||
|
||||
if (num_crects < 1)
|
||||
{
|
||||
return get_vertices_all(vertices_bytes, vertices_pointes,
|
||||
num_crects, crects, left, top, width, height);
|
||||
}
|
||||
vertices = g_new(GLfloat, num_crects * 12);
|
||||
if (vertices == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
fwidth = width / 2.0;
|
||||
fheight = height / 2.0;
|
||||
for (index = 0; index < num_crects; index++)
|
||||
{
|
||||
crect = crects + index;
|
||||
x1 = (crect->x - left) / fwidth;
|
||||
y1 = (crect->y - top) / fheight;
|
||||
x2 = ((crect->x - left) + crect->w) / fwidth;
|
||||
y2 = ((crect->y - top) + crect->h) / fheight;
|
||||
vert = vertices + index * 12;
|
||||
vert[0] = x1 - 1.0;
|
||||
vert[1] = y1 - 1.0;
|
||||
vert[2] = x1 - 1.0;
|
||||
vert[3] = y2 - 1.0;
|
||||
vert[4] = x2 - 1.0;
|
||||
vert[5] = y1 - 1.0;
|
||||
vert[6] = x1 - 1.0;
|
||||
vert[7] = y2 - 1.0;
|
||||
vert[8] = x2 - 1.0;
|
||||
vert[9] = y1 - 1.0;
|
||||
vert[10] = x2 - 1.0;
|
||||
vert[11] = y2 - 1.0;
|
||||
}
|
||||
*vertices_bytes = sizeof(GLfloat) * num_crects * 12;
|
||||
*vertices_pointes = num_crects * 6;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
xrdp_accel_assist_x11_create_pixmap(int width, int height, int magic,
|
||||
int con_id, int mon_id)
|
||||
{
|
||||
struct mon_info *mi;
|
||||
Pixmap pixmap;
|
||||
XImage *ximage;
|
||||
int img[64];
|
||||
inf_image_t inf_image;
|
||||
GLuint bmp_texture;
|
||||
GLuint enc_texture;
|
||||
|
||||
mi = g_mons + mon_id % MAX_MON;
|
||||
if (mi->pixmap != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_create_pixmap: "
|
||||
"error already setup");
|
||||
return 1;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_create_pixmap: "
|
||||
"width %d height %d, magic 0x%8.8x, con_id %d mod_id %d",
|
||||
width, height, magic, con_id, mon_id);
|
||||
pixmap = XCreatePixmap(g_display, g_root_window, width, height, 24);
|
||||
LOG(LOG_LEVEL_INFO, "pixmap %d", (int) pixmap);
|
||||
|
||||
if (g_inf_funcs[g_inf].create_image(pixmap, &inf_image) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "inf_image %p", (void *) inf_image);
|
||||
|
||||
g_memset(img, 0, sizeof(img));
|
||||
img[0] = magic;
|
||||
img[1] = con_id;
|
||||
img[2] = mon_id;
|
||||
ximage = XCreateImage(g_display, g_vis, 24, ZPixmap, 0, (char *) img,
|
||||
4, 4, 32, 0);
|
||||
XPutImage(g_display, pixmap, g_gc, ximage, 0, 0, 0, 0, 4, 4);
|
||||
XFree(ximage);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
/* texture that gets encoded */
|
||||
glGenTextures(1, &enc_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, enc_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
if (g_enc == ENC_NVENC)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_create_pixmap: "
|
||||
"using XH_YUV420");
|
||||
mi->tex_format = XH_YUV420;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height * 3 / 2, 0,
|
||||
GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
mi->get_vertices = get_vertices420;
|
||||
mi->viewport.x = 0;
|
||||
mi->viewport.y = 0;
|
||||
mi->viewport.w = width;
|
||||
mi->viewport.h = height * 3 / 2;
|
||||
}
|
||||
else if (g_enc == ENC_VA)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_create_pixmap: "
|
||||
"using XH_YUV422");
|
||||
mi->tex_format = XH_YUV422;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width / 2, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
|
||||
mi->get_vertices = get_vertices444; /* same as 444 */
|
||||
mi->viewport.x = 0;
|
||||
mi->viewport.y = 0;
|
||||
mi->viewport.w = width / 2;
|
||||
mi->viewport.h = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_create_pixmap: "
|
||||
"using XH_YUV444");
|
||||
mi->tex_format = XH_YUV444;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
|
||||
mi->get_vertices = get_vertices444;
|
||||
mi->viewport.x = 0;
|
||||
mi->viewport.y = 0;
|
||||
mi->viewport.w = width;
|
||||
mi->viewport.h = height;
|
||||
}
|
||||
/* texture that binds with pixmap */
|
||||
glGenTextures(1, &bmp_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, bmp_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (g_enc_funcs[g_enc].create_enc(width, height,
|
||||
enc_texture, mi->tex_format,
|
||||
&(mi->ei)) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
mi->pixmap = pixmap;
|
||||
mi->inf_image = inf_image;
|
||||
mi->enc_texture = enc_texture;
|
||||
mi->width = width;
|
||||
mi->height = height;
|
||||
mi->bmp_texture = bmp_texture;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if XR_DUMP_FRAMEBUFFER
|
||||
|
||||
static int g_framebuffer_file_index = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
save_fb_to_file(int width, int height)
|
||||
{
|
||||
char *pixels;
|
||||
char filename[256];
|
||||
|
||||
pixels = (char *) g_malloc(width * height * 4, 0);
|
||||
if (pixels != NULL)
|
||||
{
|
||||
glReadPixels(0, 0, width / 2, height, GL_BGRA,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
|
||||
snprintf(filename, 255, "/tmp/gl_surface%8.8x.bmp",
|
||||
g_framebuffer_file_index++);
|
||||
g_save_to_bmp(filename, pixels, width * 2, width / 2, height, 24, 32);
|
||||
g_free(pixels);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
static void
|
||||
xrdp_accel_assist_x11_run_shader(int left, int top, int width, int height,
|
||||
struct mon_info *mi,
|
||||
struct shader_info *si,
|
||||
int num_crects, struct xh_rect *crects)
|
||||
{
|
||||
GLuint vao;
|
||||
GLuint vbo;
|
||||
GLfloat *vertices;
|
||||
GLuint vertices_bytes;
|
||||
GLuint vertices_pointes;
|
||||
|
||||
/* rgb to yuv */
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, mi->bmp_texture);
|
||||
g_inf_funcs[g_inf].bind_tex_image(mi->inf_image);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, g_fb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, mi->enc_texture, 0);
|
||||
glUseProgram(si->program);
|
||||
/* setup vertices from crects */
|
||||
vertices = mi->get_vertices(&vertices_bytes, &vertices_pointes,
|
||||
num_crects, crects,
|
||||
left, top, width, height);
|
||||
if (vertices == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_run_shader: "
|
||||
"error get_vertices failed num_crects %d",
|
||||
num_crects);
|
||||
return;
|
||||
}
|
||||
glGenVertexArrays(1, &vao);
|
||||
glGenBuffers(1, &vbo);
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices_bytes, vertices, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, NULL);
|
||||
/* uniforms */
|
||||
glUniform2f(si->tex_size_loc, mi->width, mi->height);
|
||||
/* viewport and draw */
|
||||
glViewport(mi->viewport.x, mi->viewport.y, mi->viewport.w, mi->viewport.h);
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertices_pointes);
|
||||
/* cleanup */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
g_free(vertices);
|
||||
#if XR_DUMP_FRAMEBUFFER
|
||||
save_fb_to_file(width, height);
|
||||
#endif
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
g_inf_funcs[g_inf].release_tex_image(mi->inf_image);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
#if XR_DUMP_PIXMAP
|
||||
|
||||
static int g_pixmap_file_index = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
save_pixmap_to_file(Pixmap pix, int width, int height)
|
||||
{
|
||||
XImage *image;
|
||||
char filename[256];
|
||||
|
||||
image = XGetImage(g_display, pix, 0, 0, width, height, AllPlanes, ZPixmap);
|
||||
if (image != NULL)
|
||||
{
|
||||
snprintf(filename, 255, "/tmp/pixmap%8.8x.bmp", g_pixmap_file_index++);
|
||||
g_save_to_bmp(filename, image->data, width * 4, width, height, 24, 32);
|
||||
XFree(image);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
enum encoder_result
|
||||
xrdp_accel_assist_x11_encode_pixmap(int left, int top, int width, int height,
|
||||
int mon_id, int num_crects,
|
||||
struct xh_rect *crects,
|
||||
void *cdata, int *cdata_bytes,
|
||||
int flags)
|
||||
{
|
||||
struct mon_info *mi;
|
||||
struct shader_info *si;
|
||||
enum encoder_result rv;
|
||||
|
||||
mi = g_mons + mon_id % MAX_MON;
|
||||
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_accel_assist_x11_encode_pixmap: "
|
||||
"left %d top %d width %d height %d mon_id %d",
|
||||
left, top, width, height, mon_id);
|
||||
if ((width != mi->width) || (height != mi->height))
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "xrdp_accel_assist_x11_encode_pixmap: "
|
||||
"error width %d should be %d "
|
||||
"height %d should be %d",
|
||||
width, mi->width, height, mi->height);
|
||||
return ENCODER_ERROR;
|
||||
}
|
||||
#if XR_DUMP_PIXMAP
|
||||
save_pixmap_to_file(mi->pixmap, width, height);
|
||||
#endif
|
||||
si = g_si + mi->tex_format % XH_NUM_SHADERS;
|
||||
xrdp_accel_assist_x11_run_shader(left, top, width, height, mi, si,
|
||||
num_crects, crects);
|
||||
/* flush before encoding, let encoders call glFinish() as needed */
|
||||
XFlush(g_display);
|
||||
/* encode */
|
||||
rv = g_enc_funcs[g_enc].encode(mi->ei, mi->enc_texture,
|
||||
cdata, cdata_bytes, flags);
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2020-2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _XRDP_ACCEL_ASSIST_X11_H
|
||||
#define _XRDP_ACCEL_ASSIST_X11_H
|
||||
|
||||
/* generic type that can hold either a GLXPixmap(XID, unsigned int or long)
|
||||
* or EGLSurface(void*) */
|
||||
typedef intptr_t inf_image_t;
|
||||
|
||||
/* forward declaration used in xrdp_accel_assist_nvenc and
|
||||
xrdp_accel_assist_yami */
|
||||
struct enc_info;
|
||||
|
||||
int
|
||||
xrdp_accel_assist_x11_init(void);
|
||||
int
|
||||
xrdp_accel_assist_x11_get_wait_objs(intptr_t *objs, int *obj_count);
|
||||
int
|
||||
xrdp_accel_assist_x11_check_wait_objs(void);
|
||||
int
|
||||
xrdp_accel_assist_x11_delete_all_pixmaps(void);
|
||||
int
|
||||
xrdp_accel_assist_x11_create_pixmap(int width, int height, int magic,
|
||||
int con_id, int mon_id);
|
||||
enum encoder_result
|
||||
xrdp_accel_assist_x11_encode_pixmap(int left, int top, int width, int height,
|
||||
int mon_id, int num_crects,
|
||||
struct xh_rect *crects,
|
||||
void *cdata, int *cdata_bytes,
|
||||
int flags);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user