#!/bin/bash
# ssrrun - Launches an application using server-side OpenGL rendering.
#
# Copyright (c) Open Text. All Rights Reserved. Trademarks owned by OpenText.
#

# Note: This functions like vglrun, but only with options relevant to ETXCN.
# It is a complete rewrite, and not based on LGPL vglrun.

basename=$(basename $0)
basedir="$(dirname $(readlink -nf $0))"

__apiver=3
__opentext_gl_lib=libopentextglfaker.so.$__apiver
__opentext_gl_nodl_lib=libopentextglfaker-nodl.so.$__apiver
__opentext_gl_opencl_lib=libopentextglfaker-opencl.so.$__apiver
__opentext_dl_lib=libopentextdlfaker.so.$__apiver
__opentext_ge_lib=libopentextgefaker.so.$__apiver
__opentext_poll_lib=libopentextpollfaker.so.$__apiver
__opentext_ciplugin_lib=libopentextciplugin.so.$__apiver

__USE_LIBRARY_PATH__=1
__PRINT_USAGE__=0
__USE_DL__=1
__USE_GE__=0
__USE_COMPIMG__=0
__USE_POLL__=0
__BALANCE_GPU_MODE__=auto
VGL_FAKEOPENCL=2
export VGL_DISPLAY=:0

printusage()
{
cat <<END_USAGE
${basename} - Run applications with Server-Side Rendering for OpenGL
Copyright (c) Open Text. All Rights Reserved. Trademarks owned by OpenText.

Usage: '${basename}' [options] [--] <opengl_app> [opengl_app options]

Options:
 -d <dpy>    Set display for OpenGL rendering. Default is :0.
 -balancegpu <mode>
             Choose GPU from screens on chosen dpy based on mode:
               auto     Balance between GPU, video encode and memory (default)
               off      Disable GPU balancing, use -d value directly.
 -ci         Enable HCL_CompressedImage transport, if available.
 -fps <f>    Limit frame-rate to <f>
 +g          Enable gamma correction
 -g          Disable gamma correction [default]
 -gamma <f>  Set gamma correction factor
 -nodl       Disable support for apps that dynamically open libGL (dlopen)
 -opencl     Hook OpenCL libraries to make them compatible with hooked OpenGL
             (default: autodetect)
 -noopencl   Do not hook OpenCL libraries (for machines without libOpenCL.so)
 -ge         Work with apps that check for hooked functions (Hook getenv())
 +sp         Enable frame spoiling [default]. Dynamically skip frames to
               increase perceived frame-rate
 -sl         Disable Spoil Last frame spoiling optimization, use all glFlush()
 -sp         Disable frame spoiling
 -st <mode>  Set stereo mode to one of: left, right, quad [default], rc
 +sy         Enable strict syncronization bewtween 2D and 3D on each frame
 -sy         Disable strict syncronization. [default]
 +v          Enable verbose mode
 -v          Disable verbose mode [default]
 -logo       Overlay "VGL" on lower-right corner of 3D windows.
             This is useful to prove VGL is enabled.
 -poll       Work around race in poll() for apps like Ansys Mechanical.
 --version   Print version information and exit.
 -lp	     Don't set LD_LIBRARY_PATH, expect SSR libs in system path.
             (See 'copyssrtosyslib' script)
 
For more details see the VirtualGL documentation.

END_USAGE
	exit $1
}

# Not all machines may have libOpenCL.so installed, check if it is safe to use it
autodetectopencl()
{
	OCL32=0
	OCL64=0
	VGL_FAKEOPENCL=0
	ldd "${vgldir}/lib/${__opentext_gl_opencl_lib}" 2>/dev/null | grep "libOpenCL.so.* => /.*libOpenCL.so" > /dev/null && \
		OCL32=1
	ldd "${vgldir}/lib64/${__opentext_gl_opencl_lib}" 2>/dev/null | grep "libOpenCL.so.* => /.*libOpenCL.so" > /dev/null && \
		OCL64=1
	if [ "$OCL32" = 1 -a "$OCL64" = 1 ]; then
		VGL_FAKEOPENCL=1
	fi
	unset OCL32
	unset OCL64
	if [ $VGL_FAKEOPENCL -eq 1 -a "$VGL_VERBOSE" = "1" ]; then
		echo "${basename}: Autodetected OpenCL is usable."
	fi
}

checkdisplay()
{
	timeout="17" # 17 *.3 = 5.1 seconds
	DISPLAY="$2" "$1" > /dev/null 2>&1 &
	pid="$!"
	while [ $timeout -gt 0 ]; do
		kill -0 ${pid} 2>/dev/null || break
		sleep 0.3s
		let timeout-=1
	done
	if [ $timeout = 0 ]; then
		echo "${basename}: ERROR: Timed out attempting to talk to local 3D X Server '${2}'."
		echo "${basename}:        Is the display running? Have you run 'ssrconfig'?"
		kill ${pid}
		exit 1
	fi
}

#
# Sets localSSRver, the version in local install
#  and sysSSRver, the version in the system lib path.
#
getversions()
{
	# Detect arch because 32-bit libs may not be installed on a 64-bit system.
	bit=32
	arch=$(uname -m)
	[ "$arch" = "x86_64" ] && bit=64
	TESTDISPLAY=:0
	[ ! -z "${VGL_DISPLAY}" ] && TESTDISPLAY="$VGL_DISPLAY"

	# If ssrconfig was not run the login manager may have grabbed the server
        # It doesn't matter if the program returns an error because the GPU isn't
        # NVIDIA, we just want to ensure XOpenDisplay() doesn't hang.
        testapp="${basedir}/print-nv-gpu-loads${bit}"
        checkdisplay "${testapp}" "$TESTDISPLAY"

	# Though more complicated than a 'strings' approach, this method guarantees
	# to give version info from the actually-used library.
	localSSRver=$(               DISPLAY="${TESTDISPLAY}" VGL_LOG= VGL_VERBOSE=1 "${testapp}" 2>&1 | grep 'Build.*OpenText')
	sysSSRver=$(LD_LIBRARY_PATH= DISPLAY="${TESTDISPLAY}" VGL_LOG= VGL_VERBOSE=1 "${testapp}" 2>&1 | grep 'Build.*OpenText')
}


#
# Must be called after full ssr setup (LD_PRELOAD)
#
printversion()
{
	getversions
	if [ -n "$sysSSRver" -a "$localSSRver" != "$sysSSRver" ]; then
		echo "${basename}: WARNING: Mismatched SSR libraries on the system!"
		echo "${basename}:          Local install has:   '$localSSRver'"
		echo "${basename}:          System lib path has: '$sysSSRver'"
		echo "${basename}:          Fix this by running 'copyssrtosyslib'."
	else
		echo "$localSSRver"
	fi
	exit $1
}

checkvglsystemlibsinstall()
{
	getversions
	if [ -z "$sysSSRver" ]; then
		echo "${basename}: WARNING: SSR libraries don't seem to be in the system library path."
		echo "${basename}:          Some applications may fail to properly use SSR."
		echo "${basename}:          Try running 'copyssrtosyslib'."
	fi
}

setvgldir()
{
	vgldirs=( 
	 "$basedir/../3rdparty/virtualgl" #v10
	 "$basedir/3rdparty/virtualgl"    #v8
	 "$basedir/gl"                    #v7
	 )
	vgldir=UNKNOWN

	for dir in "${vgldirs[@]}"; do
		if [ -d "$dir" ]; then
			vgldir="$(readlink -nf $dir)"
			break
		fi
	done
}

setOpt()
{
case "$1" in
+*) eval $2=1;;
-*) eval $2=0;;
esac
eval export $2
}
setOptArg()
{
eval $1=$2
eval export $1
}

while [ 1 ]; do
case "$1" in
 -logo ) VGL_LOGO=1; export VGL_LOGO ;;
[+-]sy ) setOpt $1 VGL_SYNC;;
[+-]dy ) setOpt $1 VGL_DYNQUAL;;
   -st ) setOptArg VGL_STEREO $2; shift ;;
[+-]sl ) setOpt $1 VGL_SPOILLAST;;
[+-]sp ) setOpt $1 VGL_SPOIL;;
   -d  ) setOptArg VGL_DISPLAY $2; shift ;;
-balancegpu ) setOptArg __BALANCE_GPU_MODE__ $2; shift ;;
-gamma ) setOptArg VGL_GAMMA $2; shift ;;
 -nodl ) __USE_DL__=0;;
 -opencl ) VGL_FAKEOPENCL=1;;
 -noopencl ) VGL_FAKEOPENCL=0;;
   -ge ) __USE_GE__=1;;
   -ci ) __USE_COMPIMG__=1;;
 -poll ) __USE_POLL__=1;;
   -lp ) __USE_LIBRARY_PATH__=0;;
 [+-]g ) setOpt $1 VGL_GAMMA;;
 [+-]v ) setOpt $1 VGL_VERBOSE;;
   -tr ) setOpt $1 VGL_TRACE=1;;
  -log ) setOptArg VGL_LOG $2; shift ;;
  -fps ) setOptArg VGL_FPS $2; shift ;;
-window ) VGL_WINDOW=1; export VGL_WINDOW ;;
-h|--help ) printusage 0 ;;
-version|--version ) __PRINT_VERSION__=1; break; ;;
    -- ) shift ; break ;;
    -* ) echo -e "${basename}: ERROR: Invalid option: '$1'\n"; printusage 1 ;;
     * ) break ;;
esac
shift
[ $# = 0 ] && break
done

[ -z "$1" ] && printusage 1

if [ -z "$VGL_COMPRESS" ]; then
	VGL_COMPRESS=proxy
	if [ "$__USE_COMPIMG__" = 1 -a -z "$VGL_TRANSPORT" ]; then
		xdpyinfo=$(which xdpyinfo 2>/dev/null)
		if [ ! -z "$xdpyinfo" ]; then
			$xdpyinfo 2>&1 | grep "HCL_CompressedImage" > /dev/null 2>&1 && \
				 export VGL_TRANSPORT=${__opentext_ciplugin_lib}
		fi
	fi
	export VGL_COMPRESS
fi

if [ "$__BALANCE_GPU_MODE__" != "off" ]; then
	getssrdisplay="$(dirname $0)/getssrdisplay.sh"
	dpy=$("$getssrdisplay" "$__BALANCE_GPU_MODE__" "$VGL_DISPLAY")
	if [ $? -ne 0 -o -z "$dpy" ]; then
	        if [ "$__PRINT_VERSION__" != "1" ]; then
                        echo "${basename}: NOTE: Failed to query GPU loads for -balancegpu option. Will use GPU on $VGL_DISPLAY"
	        fi
	else
		export VGL_DISPLAY=$dpy
	fi
fi

setvgldir $0

VGLLIBDIR32="${vgldir}/lib"
VGLLIBDIR64="${vgldir}/lib64"

if [ ! -f "${VGLLIBDIR32}/${__opentext_gl_lib}" ]; then
	echo "Error: Installation path is invalid:"
	echo " [${vgldir}]"
	exit 1
fi

if [ $VGL_FAKEOPENCL -eq 2 ]; then
	autodetectopencl
fi

gllib=${__opentext_gl_lib}
if [ $__USE_DL__ -eq 0 ]; then
gllib=${__opentext_gl_nodl_lib}
elif [ $VGL_FAKEOPENCL -eq 1 ]; then
gllib=${__opentext_gl_opencl_lib}
fi

# Clear any prior (possibly incompatible) VGL libs
if [ ! -z "$LD_PRELOAD" ]; then
	LD_PRELOAD=`echo $LD_PRELOAD|sed 's|libopentext[a-z]*faker[-a-z]*\.so\.[0-9]:*||g'`
fi

case "`uname`" in
Linux )
	if [ "$__USE_LIBRARY_PATH__" = 1 ]; then
		[ -n "$LD_LIBRARY_PATH" ] && LD_LIBRARY_PATH=":$LD_LIBRARY_PATH"
		LD_LIBRARY_PATH=$VGLLIBDIR32:$VGLLIBDIR64:$LD_LIBRARY_PATH
		export LD_LIBRARY_PATH
	fi
	[ -n "$LD_PRELOAD" ] && LD_PRELOAD=":$LD_PRELOAD"
	LD_PRELOAD=${gllib}$LD_PRELOAD
	if [ "$__PRINT_VERSION__" != "1" ]; then # avoid extra messages if +v is used with --version
		[ $__USE_DL__ = 1 ]   && LD_PRELOAD=${__opentext_dl_lib}:$LD_PRELOAD
		[ $__USE_GE__ = 1 ]   && LD_PRELOAD=${__opentext_ge_lib}:$LD_PRELOAD
		[ $__USE_POLL__ = 1 ] && LD_PRELOAD=${__opentext_poll_lib}:$LD_PRELOAD
	fi
	export LD_PRELOAD
	checkvglsystemlibsinstall
;;
* )
	echo "This platform isn't supported."
	exit
;;
esac

export VGL_ISACTIVE=1
export VGL_FAKEOPENCL

[ "$__PRINT_VERSION__" = "1" ] && printversion 0

exec ${1+"$@"}
