diff options
67 files changed, 3114 insertions, 480 deletions
@@ -23,11 +23,15 @@ <classpathentry kind="src" path="test/junit"/> <classpathentry kind="src" path="jcpp/src/main/java"/> <classpathentry kind="src" path="jcpp/src/test/java"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Ant"/> <classpathentry kind="lib" path="make/lib/antlr.jar" sourcepath="make/lib/antlr-src.zip"/> <classpathentry kind="lib" path="make/lib/junit.jar" sourcepath="make/lib/junit-sources.jar"/> <classpathentry kind="lib" path="make/lib/semantic-versioning/semver.jar" sourcepath="make/lib/semantic-versioning/semver-src.zip"/> <classpathentry kind="lib" path="make/lib/android-sdk/24/android.jar" sourcepath="make/lib/android-sdk/24/android-java-src.zip"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"> + <attributes> + <attribute name="module" value="true"/> + </attributes> + </classpathentry> <classpathentry kind="output" path="build/eclipse-classes"/> </classpath> @@ -3,3 +3,4 @@ make/GnuCTreeParserTokenTypes.txt make/STDCTokenTypes.txt build*/ build-temp +*.log diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..e50443c --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,15 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..7103be7 --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/doc/HowToBuild.html b/doc/HowToBuild.html index 168cc27..dc4e680 100644 --- a/doc/HowToBuild.html +++ b/doc/HowToBuild.html @@ -38,10 +38,10 @@ <ul> <li> <b>Java</b> <ul> - <li>Build & Runtime: An <a href="http://openjdk.java.net/">OpenJDK</a> 11 compliant SDK.</li> + <li>Build & Runtime: An <a href="http://openjdk.java.net/">OpenJDK</a> 17 compliant SDK.</li> <li>Runtime: An OpenJDK 8 compliant JRE.</li> </ul> - You may find an appropriate <a href="http://openjdk.java.net/">OpenJDK</a> build @ <a href="https://adoptopenjdk.net/">AdoptOpenJDK</a>.<br/> + You may find an appropriate <a href="http://openjdk.java.net/">OpenJDK</a> build @ <a href="https://adoptium.net/temurin/releases/">Adoptium</a>.<br/> <br/> Or you may try one of the following SDK's and/or Runtimes: <ul> @@ -55,7 +55,7 @@ <li> Use your Unix distribution's version, if available, or</li> <li> <a href="http://www.kernel.org/pub/software/scm/git/">Source Code for GNU/Linux, MacOS, ..</a>, or</li> <li> Git on Windows is provided by <a href="https://cygwin.com">cygwin</a></li> - <li> Git ≥ 2.11 on MacOS is provided by Xcode ≥ 8.3.3</li> + <li> Git ≥ 2.37 provided by Xcode ≥ 14</li> </ul> </li> @@ -63,7 +63,7 @@ <ul> <li> <b><a href="https://www.freebsd.org/releases/">FreeBSD</a></b> 12 or later <i>(todo: test)</i> <ul> - <li>openjdk11</li> + <li>openjdk17</li> <li>ant</li> <li>git</li> <li>awk</li> @@ -73,13 +73,13 @@ </ul> </ul> </li> - <li> <b>GNU Linux</b> x86, 32- and 64-bit as well as Arm64, etc<br/> + <li> <b>GNU Linux</b> x86_64 as well as Arm64, etc<br/> You may have to install a few developer packages ... <ul> - <li> <b>Debian</b> 10 or later + <li> <b>Debian</b> 11 or later <ul> - <li>openjdk-11-jre</li> - <li>openjdk-11-jdk</li> + <li>openjdk-17-jre</li> + <li>openjdk-17-jdk</li> <li>ant</li> <li>git</li> <li>gawk</li> @@ -89,28 +89,19 @@ </ul> One liner install command: <ul> - <li><b>Debian</b> 10 Buster + <li><b>Debian</b> 11 Bullseye <pre> -apt-get install openjdk-11-jre openjdk-11-jdk ant git-all gawk p7zip-full gcc cmake +apt-get install openjdk-17-jre openjdk-17-jdk ant git-all gawk p7zip-full gcc cmake </pre></li> </ul> Optional: Add <i>kernel</i> build utilities: <pre> apt-get install kernel-package build-essential </pre> - Optional: Add <i>multiarch</i> i386 next to amd64 - <ul> - <li><b>Debian</b> 10 Buster - <pre> -dpkg --add-architecture i386 -apt-get update -apt-get install lib32z1 lib32ncurses5 gcc-multilib lib32gcc1 lib32gomp1 lib32itm1 lib32quadmath0 libudev1:i386 libc6-i386 libc6-dev-i386 g++-multilib lib32stdc++6 openjdk-11-jre:i386 openjdk-11-jdk:i386 - </pre></li> - </ul> </li> <li> <b>OpenSuSE</b> 15.0 or later <ul> - <li>java-11-openjdk</li> + <li>java-17-openjdk</li> <li>ant</li> <li>git</li> <li>gawk</li> @@ -121,7 +112,7 @@ apt-get install lib32z1 lib32ncurses5 gcc-multilib lib32gcc1 lib32gomp1 lib32itm </li> <li> <b>CentOS 7 / Red Hat Enterprise Linux 7.6</b> or later<br/> <ul> - <li>java-11-openjdk</li> + <li>java-17-openjdk</li> <li>ant</li> <li>git</li> <li>gawk</li> @@ -144,53 +135,73 @@ apt-get install lib32z1 lib32ncurses5 gcc-multilib lib32gcc1 lib32gomp1 lib32itm <li><a href="https://www.openindiana.org/">OpenIndiana</a> using illumus's OpenSolaris continuation <i>(todo: test)</i></li> </ul> </li> - <li> <b>MacOS and iOS</b> Intel and Arm64 + <li> <b>MacOS and iOS</b> x86_64 and aarch64 <ul> - <li>git ≥ 2.11 provided by Xcode ≥ 8.3.3</li> + <li>Build machine: <a href="http://www.apple.com/macosx/">Mac OS</a> 12.6.5 (Monterey) + <ul> + <li>Lowest test machine: <a href="http://www.apple.com/macosx/">Mac OS</a> 10.13.6 (High Sierra)</li> + <li>Minimum deployment target: <a href="http://www.apple.com/macosx/">Mac OS</a> 10.7 (Lion)</li> + </ul></li> + <li><a href="http://developer.apple.com/technologies/xcode.html">Xcode</a> 14.2 for clang, etc (included in MacOS)</li> + <li>MacOS SDK 11.3 from a previous XCode version or <a href="https://github.com/phracker/MacOSX-SDKs">from this alternative site</a> + <ul> + <li><i>export SDKROOT=macosx11.3</i></li> + <li>We use <i>-mmacosx-version-min=10.7</i> (Lion 10.7) minimum deployment target.</li> + </ul></li> + <li>git ≥ 2.37 provided by Xcode ≥ 14</li> <li>awk is provided by MacOS</li> - <li><a href="https://cmake.org/">CMake 3.15.2</a>, and install the <a href="https://stackoverflow.com/questions/30668601/installing-cmake-command-line-tools-on-a-mac">command line tools</a></li> - <li><a href="http://www.apple.com/macosx/">Mac OS</a> 10.13 or later (note: may not work with earlier releases) </li> - <li><a href="http://developer.apple.com/technologies/xcode.html">Xcode</a> 8.3.3 or later for gcc, etc (included in MacOS)</li> + <li><a href="https://cmake.org/">CMake 3.25.1</a>, and install the <a href="https://stackoverflow.com/questions/30668601/installing-cmake-command-line-tools-on-a-mac">command line tools</a> + <ul> + <li>Install symlinks to <i>/usr/local/bin</i>, run: <i>sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install</i></li> + </ul></li> + <li><a href="https://7-zip.org/">7-Zip 21.07</a> x86_64 and arm64 version</li> + <li>See also <a href="JogAmpMacOSVersions.md">MacOS Versions Related to JogAmp</a></li> </ul> - </li> - <li> <b>Windows</b>/x86 (32 bit) + Prepare fat universal OpenJDK libraries <ul> - <li>Windows XP or later </li> - <li>git is provided by <a href="https://cygwin.com">cygwin</a></li> - <li>gawk is provided by <a href="https://cygwin.com">cygwin</a></li> - <li> <a href="http://mingw-w64.org/">MinGW64</a> (<a href="https://sourceforge.net/projects/mingw-w64/files/">files on sourceforge</a>) - <ul> - <li> <a href="https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/8.1.0/threads-win32/sjlj/i686-8.1.0-release-win32-sjlj-rt_v6-rev0.7z">i686-8.1.0-release-win32-sjlj-rt_v6-rev0.7z</a> - <ul> - <li>version: 8.1.0</li> - <li>host: x32</li> - <li>threading: win32</li> - <li>exceptions: SJLJ</li> - <li>revision: 0</li> - </ul></li> - </ul> - </li> - <li><a href="https://cmake.org/">CMake 3.15.2</a> 32bit version</li> + <li>Open a terminal in your home folder, e.g. <i>/Users/jogamp</i></li> + <li>The OpenJDK library folder of each target platform, x86_64 or aarch64, is <i>/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/lib</i></li> + <li>Transfer the x86_64 OpenJDK library folder to <i>temurin-17.jdk.amd64.lib</i><li> + <li>Transfer the aarch64 OpenJDK library folder to <i> temurin-17.jdk.arm64.lib</i></li> + <li>Run the script <i>gluegen/make/scripts/make.macosx.jdk_lipo_libs.sh</i></li> + <li>Fat universal OpenJDK libraries are produced into <i>temurin-17.jdk.fat.lib</i></li> </ul> + Now we have to tell the <i>gluegen</i> build framework to use <i>temurin-17.jdk.fat.lib</i>, + by adding an <i>ant</i> macro in <i>$HOME/gluegen.properties</i> + <pre> + java.lib.dir.platform=/Users/jogamp/temurin-17.jdk.fat.lib + </pre> + Replace <i>jogamp</i> with your user name. </li> <li> <b>Windows</b>/x86_64 (64-bit) <ul> - <li>Windows XP or later </li> + <li>Windows 7 or later </li> <li>git is provided by <a href="https://cygwin.com">cygwin</a></li> <li>gawk is provided by <a href="https://cygwin.com">cygwin</a></li> - <li> <a href="http://mingw-w64.org/">MinGW64</a> (<a href="https://sourceforge.net/projects/mingw-w64/files/">files on sourceforge</a>) + <li> <a href="http://mingw-w64.org/">MinGW64</a> (<a href="https://github.com/niXman/mingw-builds-binaries/releases">files on github</a>) <ul> - <li> <a href="https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-win32/sjlj/x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.7z">x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.7z</a> + <li> <a href="https://github.com/niXman/mingw-builds-binaries/releases/download/12.2.0-rt_v10-rev2/x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.7z">x86_64-12.2.0-release-posix-seh-msvcrt-rt_v10-rev2.7z</a> <ul> - <li>version: 8.1.0</li> + <li>version: 12.2.0</li> <li>host: x64</li> - <li>threading: win32</li> - <li>exceptions: SJLJ</li> - <li>revision: 0</li> + <li>threading: posix</li> + <li>exceptions: seh</li> + <li>c-runtime: msvcrt</li> + <li>revision: 2</li> </ul></li> + <li> <s><a href="https://github.com/niXman/mingw-builds-binaries/releases/download/12.2.0-rt_v10-rev2/x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z">x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z</a> + <ul> + <li>version: 12.2.0</li> + <li>host: x64</li> + <li>threading: win32</li> + <li>exceptions: seh</li> + <li>c-runtime: msvcrt</li> + <li>revision: 2</li> + </ul></s></li> </ul> </li> - <li><a href="https://cmake.org/">CMake 3.15.2</a> 64bit version</li> + <li><a href="https://cmake.org/">CMake 3.25.1</a> 64bit version</li> + <li><a href="https://www.7-zip.org/">7-Zip 22.01</a> 64bit version</li> </ul> </li> </ul> diff --git a/doc/JogAmpMacOSVersions.md b/doc/JogAmpMacOSVersions.md new file mode 100644 index 0000000..924c53f --- /dev/null +++ b/doc/JogAmpMacOSVersions.md @@ -0,0 +1,54 @@ +# MacOS Versions Related to JogAmp + +References + +- [Mac OS Version History (wiki)](https://en.wikipedia.org/wiki/MacOS_version_history). +- [Xcode Version Comparison Table (wiki)](https://en.wikipedia.org/wiki/Xcode#Version_comparison_table) + +## Overview + +| MacOS Version | Release Name | Darwin Version | JogAmp Relation | +|:--------------|:-------------|:---------------|:-------------------------------------------| +| 10.7 | Lion | 11 | Min deployment target | +| | | | | +| 10.13 | High Sierra | 17 | Test node 10.13.6, `x86_64` | +| 10.14 | Mojave | 18 | | +| 10.15 | Catalina | 19 | | +| | | | | +| 11 | Big Sur | 20 | | +| 12 | Monterey | 21 | Build node 12.6.5, w/ Xcode 14.2, `x86_64` | +| 13 | Ventura | 22 | Test node 13.1, `arm64` | + +## OpenJDK + +Available Java(tm) VMs + +- [OpenJDK](http://openjdk.java.net/) build @ [Adoptium](https://adoptium.net/temurin/releases/) + - [Adoptium Supported MacOS Versions](https://adoptium.net/supported-platforms/) + - MacOS 10.15, 11, 12, 13 for `x86_64` and `arm64` + +## JogAmp Build and Test Setup + +### MacOS 12.6.5 (Monterey), Darwin 21, `x86_64` + + - Build and main test machine + - XCode 14.2 w/ SDK 11.3 + - `export SDKROOT=macosx11.3` (*MacOS SDK*) + - `-mmacosx-version-min=10.7` (*Miniumum deployment target*) + - OpenJDK Temurin 17.0.5+8 + +### MacOS 10.13.6 (High Sierra), Darwin 17, `x86_64` + + - Test machine + - OpenJDK Temurin 17.0.5+8 + +### MacOS 13.1 (Ventura), Darwin 22, `arm64` + + - Test machine + - OpenJDK Temurin 17.0.5+8 + +## Change History + +| Date | Note | +|:-----------|:-----------------------------------------| +| 2023-05-06 | Initial Version for JogAmp Release 2.5.0 | diff --git a/make/build-test.xml b/make/build-test.xml index a83333d..85437f6 100644 --- a/make/build-test.xml +++ b/make/build-test.xml @@ -177,7 +177,9 @@ <src path="${test.jcpp.base.dir}"/> <src path="${build_t.gen}" /> </javac> + </target> + <target name="jar.build"> <jar destfile="${gluegen-test-util.jar}"> <fileset dir="${build_t.java}"> <include name="${test.junit.util.rel}/**/*.class"/> @@ -198,7 +200,7 @@ </jar> </target> - <target name="android.package" depends="java.generate,java.build,native.build" if="isAndroid"> + <target name="android.package" depends="java.generate,java.build,native.build,jar.build" if="isAndroid"> <aapt.signed assetsdir="resources/assets-test" jarbuilddir="${build_t}" @@ -591,7 +593,7 @@ chmod 644 ${results}/* \${line.separator} </gluegen> </target> - <target name="junit.test1.c.build" depends="junit.test1i.c.build, c.rename.lib.test1.mingw, junit.test1p1.c.build, c.rename.lib.test1p1.mingw, junit.test1p2.c.build, c.rename.lib.test1p2.mingw" unless="build.javaonly" /> + <target name="junit.test1.c.build" depends="junit.test1i.c.build, junit.test1p1.c.build, junit.test1p2.c.build" unless="build.javaonly" /> <!-- this is the test1 implementation --> <target name="junit.test1i.c.build"> @@ -609,9 +611,6 @@ chmod 644 ${results}/* \${line.separator} linker.cfg.id="linker.test1.dll.cfg.id"/> </target> - <target name="c.rename.lib.test1.mingw" if="isMingW"> - <move file="${build_t.lib}/libtest1.so" tofile="${build_t.lib}/test1.dll" /> - </target> <!-- this is a fixed binding to the test1 implementation --> <target name="junit.test1p1.c.build"> @@ -632,9 +631,6 @@ chmod 644 ${results}/* \${line.separator} compiler.cfg.id="${compiler.cfg.id}" linker.cfg.id="linker.test1.fixed.cfg.id"/> </target> - <target name="c.rename.lib.test1p1.mingw" if="isMingW"> - <move file="${build_t.lib}/libBindingtest1p1.so" tofile="${build_t.lib}/Bindingtest1p1.dll" /> - </target> <!-- this is a dynamic lookup binding to the test1 implementation --> <target name="junit.test1p2.c.build"> @@ -654,9 +650,6 @@ chmod 644 ${results}/* \${line.separator} compiler.cfg.id="${compiler.cfg.id}" linker.cfg.id="linker.test1.runtime.cfg.id"/> </target> - <target name="c.rename.lib.test1p2.mingw" if="isMingW"> - <move file="${build_t.lib}/libBindingtest1p2.so" tofile="${build_t.lib}/Bindingtest1p2.dll" /> - </target> <!-- diff --git a/make/build.xml b/make/build.xml index 8cd6ea1..a4afadb 100644 --- a/make/build.xml +++ b/make/build.xml @@ -440,12 +440,6 @@ <target name="c.configure" depends="gluegen.cpptasks.detect.os,gluegen.cpptasks.setup.compiler,declare.win32,declare.linux,declare.android,declare.solaris,declare.macosx,declare.ios.amd64,declare.ios.arm64,declare.freebsd,declare.hpux,gluegen.cpptasks.configure.compiler" /> - <target name="c.rename.lib.mingw" if="isMingW"> - <!-- FIXME: this is a hack; the cpptask should have an option to change the - suffix or at least understand the override from .so to .dll --> - <move file="${build}/obj/libgluegen_rt.so" tofile="${build}/obj/gluegen_rt.dll" /> - </target> - <target name="c.manifest" if="isVC8Family"> <!-- exec mt, the Microsoft Manifest Tool, to include DLL manifests in order to resolve the location of msvcr80.dll --> <msvc.manifest objdir="${build}/obj" dllname="gluegen_rt" /> @@ -526,8 +520,6 @@ </cc> - <antcall target="c.rename.lib.mingw" inheritRefs="true" /> - <gluegen.make.libsymbols builddir="${build}" nativelib="${gluegen.lib.dir}/${output.lib.name.os}" symbolsfile="${gluegen.lib.dir}/${native.library.prefix}${output.lib.name}.symbols" /> @@ -816,6 +808,7 @@ excludes="${gluegen.excludes.all} ${gluegen-rt.classes} ${java.part.android}" memoryMaximumSize="${javac.memorymax}" encoding="UTF-8" + source="${target.sourcelevel}" target="${target.targetlevel}" debug="${javacdebug}" debuglevel="${javacdebuglevel}"> <src path="${src.jcpp}" /> @@ -1339,12 +1332,12 @@ <copy todir="${archive}"> <fileset dir=".." includes="LICENSE.txt"/> <fileset dir="${build}" includes="artifact.properties"/> - <fileset dir="${build}" includes="gluegen-java-src.zip"/> </copy> <mkdir dir="${archive}/jar" /> <copy todir="${archive}/jar"> <fileset dir="${build}" includes="gluegen*.jar"/> <fileset dir="${build}" includes="*.apk"/> + <fileset dir="${build}" includes="gluegen-java-src.zip"/> </copy> <mkdir dir="${archive}/lib" /> <copy todir="${archive}/lib"> diff --git a/make/gluegen-cpptasks-base.xml b/make/gluegen-cpptasks-base.xml index 30cadf3..746f9cc 100755 --- a/make/gluegen-cpptasks-base.xml +++ b/make/gluegen-cpptasks-base.xml @@ -221,20 +221,10 @@ <condition property="c.strip.libraries"><isfalse value="${c.compiler.debug}"/></condition> <!-- NOTE: the values of the macos<arch> attributes will not be overridden if already set externally --> - <property name="macosppc" value="false" /> - <property name="macosx64" value="true" /> - <property name="macosx32" value="false" /> <!-- we disable 32bit on OSX for good now --> + <property name="macosppc" value="false" /> <!-- permanently disabled --> + <property name="macosx32" value="false" /> <!-- permanently disabled --> + <property name="macosx64" value="true" /> <!-- for x86_64 and arm64 --> - <!-- Need a way to be able to disable the macosx64 property specification in a build.xml --> - <condition property="use.macosppc"> - <istrue value="${macosppc}" /> - </condition> - <condition property="use.macosx32"> - <and> - <istrue value="${macosx32}" /> - <os family="mac"/> - </and> - </condition> <condition property="use.macosx64"> <and> <istrue value="${macosx64}" /> @@ -801,6 +791,7 @@ <echo message="os and arch: ${os.and.arch}" /> <echo message="os and arch.dot: ${os.and.arch.dot}" /> <echo message="os and arch.slash: ${os.and.arch.slash}" /> + <echo message="native library: prefix '${native.library.prefix}', suffix '${native.library.suffix}'" /> </target> <target name="gluegen.cpptasks.detect.os" depends="gluegen.properties.load.user,gluegen.cpptasks.detect.os.custom,gluegen.cpptasks.detect.os.1,gluegen.cpptasks.detect.os.2"> @@ -1236,20 +1227,19 @@ </defineset> </compiler> - <!-- MacOSX compiler configuration --> + <!-- + MacOSX compiler configuration. + See and sync-with doc/HowToBuild.html and doc/JogAmpMacOSVersions.md + --> <compiler id="compiler.cfg.macosx" name="${gcc.compat.compiler}"> - <!-- Note: Apple doesn't seem to provide ppc binaries on Snow Leopard --> - <compilerarg value="-arch" if="use.macosppc"/> - <compilerarg value="ppc" if="use.macosppc"/> - <compilerarg value="-arch" if="use.macosx32"/> - <compilerarg value="i386" if="use.macosx32"/> <compilerarg value="-arch" if="use.macosx64"/> <compilerarg value="x86_64" if="use.macosx64"/> - <!-- Note: Apple doesn't seem to provide ppc64 binaries on Leopard --> + <compilerarg value="-arch" if="use.macosx64"/> + <compilerarg value="arm64" if="use.macosx64"/> <compilerarg value="-Wmost" /> <compilerarg value="-ObjC" /> - <compilerarg value="-mmacosx-version-min=10.5"/> + <compilerarg value="-mmacosx-version-min=10.7"/> <!-- sysincludepath path="${macosx.sdkroot}" if="macosx.sdkroot"/ --> <defineset> <define name="_DEBUG" if="c.compiler.use-debug"/> @@ -1479,13 +1469,11 @@ <linker id="linker.cfg.macosx" name="${gcc.compat.compiler}"> <!-- compilerarg value="-v"/ --> - <linkerarg value="-arch" if="use.macosppc"/> - <linkerarg value="ppc" if="use.macosppc"/> - <linkerarg value="-arch" if="use.macosx32"/> - <linkerarg value="i386" if="use.macosx32"/> <linkerarg value="-arch" if="use.macosx64"/> <linkerarg value="x86_64" if="use.macosx64"/> - <linkerarg value="-mmacosx-version-min=10.5"/> + <linkerarg value="-arch" if="use.macosx64"/> + <linkerarg value="arm64" if="use.macosx64"/> + <linkerarg value="-mmacosx-version-min=10.7"/> <linkerarg value="-static-libgcc" if="isGCC"/> <linkerarg value="-static-libstdc++" if="isGCC"/> </linker> diff --git a/make/jogamp-androidtasks.xml b/make/jogamp-androidtasks.xml index 3289a2b..9236496 100644 --- a/make/jogamp-androidtasks.xml +++ b/make/jogamp-androidtasks.xml @@ -159,6 +159,7 @@ <echo>aapt.signed ${m.aapt.apkbasename}: compiling R.java...</echo> <javac encoding="${m.aapt.java.encoding}" + includeAntRuntime="false" source="${target.sourcelevel}" target="${target.targetlevel}" bootclasspath="${target.rt.jar}" @@ -180,7 +181,7 @@ <!-- exec dir="." executable="dx" logError="true" failonerror="true" failifexecutionfails="true"> <arg line="- -dex"/> <arg line="- -output=${m.aapt.dex.file}"/> - <arg line="- -min-sdk-version=${android.api.level.min}"/> + <arg line="- -min-sdk-version=${android.api.level}"/> <arg line="@{jarbuilddir}/@{jarbasename}.jar"/> <arg line="${m.aapt.build.apk}/temp/classes"/> </exec --> @@ -191,7 +192,9 @@ <arg line="--classpath ${target.rt.jar}"/> <d8-classpaths/> - <arg line="--min-api ${android.api.level.min}"/> + <arg line="--min-api ${android.api.level}"/> + + <!-- arg line="- -no-desugaring"/ --> <arg line="--release"/> <!-- arg line="- -debug"/ --> @@ -235,11 +238,13 @@ <!-- Be Java6 keytool/jarsigner compatible, and hence Android compatible --> <arg value="-sigalg"/> - <arg value="MD5withRSA"/> + <arg value="SHA256withRSA"/> <arg value="-keyalg"/> <arg value="RSA"/> <arg value="-keysize"/> - <arg value="1024"/> + <arg value="2048"/> + <arg value="-validity"/> + <arg value="365"/> <arg value="-keystore" /> <arg value="${m.aapt.build.apk}/debug.keystore" /> @@ -260,8 +265,8 @@ <!-- Be Java6 keytool/jarsigner compatible, and hence Android compatible --> <echo>aapt.signed ${m.aapt.apkbasename}: signing w/ key @{keystore.alias} @ ${m.aapt.keystore.file}</echo> <!-- signjar - sigalg="MD5withRSA" - digestalg="SHA1" + sigalg="SHA256withRSA" + digestalg="SHA256" jar="${m.aapt.unsigned.package.file.name}" signedjar="${m.aapt.signed.file.name}" keystore="${m.aapt.keystore.file}" @@ -273,9 +278,9 @@ <exec dir="." executable="jarsigner" failonerror="true"> <!-- Be Java6 keytool/jarsigner compatible, and hence Android compatible --> <arg value="-sigalg"/> - <arg value="MD5withRSA"/> + <arg value="SHA256withRSA"/> <arg value="-digestalg"/> - <arg value="SHA1"/> + <arg value="SHA256"/> <arg value="-keystore" /> <arg value="${m.aapt.keystore.file}" /> diff --git a/make/jogamp-env.xml b/make/jogamp-env.xml index a5575f8..cc8ed71 100755 --- a/make/jogamp-env.xml +++ b/make/jogamp-env.xml @@ -8,7 +8,7 @@ - Java 1.8 (Level 8.0) - Android SDK API level 24 (Version 7.0 Nougat, released August 2016) - Official production builds are performed _on_ OpenJDK 11 + Official production builds are performed _on_ OpenJDK 11 or 17 and a Java JDK 11 or greater is required! Target Java 8 baseline is chosen today, June 2019, @@ -74,19 +74,65 @@ </condition> </fail> + <condition property="minJava21" value="true"> + <or> + <equals arg1="${ant.java.version}" arg2="21"/> + <equals arg1="${ant.java.version}" arg2="22"/> + <equals arg1="${ant.java.version}" arg2="23"/> + <equals arg1="${ant.java.version}" arg2="24"/> + <equals arg1="${ant.java.version}" arg2="25"/> + <equals arg1="${ant.java.version}" arg2="26"/> + <equals arg1="${ant.java.version}" arg2="27"/> + <equals arg1="${ant.java.version}" arg2="28"/> + </or> + </condition> + <echo message="minJava21 ${minJava21}"/> + + <condition property="minJava17" value="true"> + <or> + <equals arg1="${ant.java.version}" arg2="17"/> + <equals arg1="${ant.java.version}" arg2="18"/> + <equals arg1="${ant.java.version}" arg2="19"/> + <equals arg1="${ant.java.version}" arg2="20"/> + <istrue value="${minJava21}"/> + </or> + </condition> + <echo message="minJava17 ${minJava17}"/> + + <condition property="minJava11" value="true"> + <or> + <equals arg1="${ant.java.version}" arg2="11"/> + <equals arg1="${ant.java.version}" arg2="12"/> + <equals arg1="${ant.java.version}" arg2="13"/> + <equals arg1="${ant.java.version}" arg2="14"/> + <equals arg1="${ant.java.version}" arg2="15"/> + <equals arg1="${ant.java.version}" arg2="16"/> + <istrue value="${minJava17}"/> + </or> + </condition> + <echo message="minJava11 ${minJava11}"/> + + <condition property="minJava9" value="true"> + <or> + <equals arg1="${ant.java.version}" arg2="9"/> + <istrue value="${minJava11}"/> + </or> + </condition> + <echo message="minJava9 ${minJava9}"/> + + <condition property="minJava8" value="true"> + <or> + <equals arg1="${ant.java.version}" arg2="1.8"/> + <istrue value="${minJava9}"/> + </or> + </condition> + <echo message="minJava8 ${minJava8}"/> + <!-- Only for junit runtime tests Java [8-10] is allowed, for building Java 11 is required. --> <fail message="Unsupported Java version: ${ant.java.version}. Make sure that the version of Java is 1.8 or greater."> <condition> <not> - <or> - <equals arg1="${ant.java.version}" arg2="1.8"/> - <equals arg1="${ant.java.version}" arg2="9"/> - <equals arg1="${ant.java.version}" arg2="10"/> - <equals arg1="${ant.java.version}" arg2="11"/> - <equals arg1="${ant.java.version}" arg2="12"/> - <equals arg1="${ant.java.version}" arg2="13"/> - <equals arg1="${ant.java.version}" arg2="14"/> - </or> + <istrue value="${minJava8}"/> </not> </condition> </fail> @@ -101,15 +147,7 @@ </tstamp> <condition property="javadoc.xarg1" value="-Xdoclint:none" else="-J-Ddummy=val"> - <or> - <equals arg1="${ant.java.version}" arg2="1.8"/> - <equals arg1="${ant.java.version}" arg2="9"/> - <equals arg1="${ant.java.version}" arg2="10"/> - <equals arg1="${ant.java.version}" arg2="11"/> - <equals arg1="${ant.java.version}" arg2="12"/> - <equals arg1="${ant.java.version}" arg2="13"/> - <equals arg1="${ant.java.version}" arg2="14"/> - </or> + <istrue value="${minJava8}"/> </condition> <echo message="javadoc.xarg1 ${javadoc.xarg1}"/> @@ -122,7 +160,7 @@ <echo message="jogamp.jar.codebase ${jogamp.jar.codebase}"/> <property name="jogamp.version.major" value="2"/> - <property name="jogamp.version.minor" value="4"/> + <property name="jogamp.version.minor" value="5"/> <property name="jogamp.version.submi" value="0"/> <property name="jogamp.version.devel" value="-rc-${version.timestamp}"/> <!-- Devel RC Tag --> <!-- property name="jogamp.version.devel" value=""/ --> <!-- Release tag --> @@ -164,8 +202,6 @@ </not> </condition> - <property name="android.api.level.min" value="21" /> - <condition property="android.api.level" value="${env.ANDROID_API_LEVEL}" else="24"> <not> <equals arg1="${env.ANDROID_API_LEVEL}" arg2="$${env.ANDROID_API_LEVEL}" casesensitive="true" /> diff --git a/make/lib/cpptasks-version.txt b/make/lib/cpptasks-version.txt index 339d395..231d444 100755 --- a/make/lib/cpptasks-version.txt +++ b/make/lib/cpptasks-version.txt @@ -1,5 +1,6 @@ Current cpptasks is from <http://jogamp.org/git/?p=ant-cpptasks.git;a=summary> +commit 19c854265956942497dc89444a9ee84f18383671 Original cpptasks is from <http://ant-contrib.sourceforge.net/cpptasks/index.html> diff --git a/make/lib/cpptasks.jar b/make/lib/cpptasks.jar Binary files differindex dbefd44..bd29273 100644 --- a/make/lib/cpptasks.jar +++ b/make/lib/cpptasks.jar diff --git a/make/scripts/check-java-major-version.sh b/make/scripts/check-java-major-version.sh index 49c0445..fc9f53c 100755 --- a/make/scripts/check-java-major-version.sh +++ b/make/scripts/check-java-major-version.sh @@ -12,7 +12,7 @@ function dump_versions() { #dump_version jogamp.common.Debug javap -v `find . -name '*.class'` | grep -e '^Classfile' -e 'major version' #for i in `find . -name '*.class'` ; do - # dump_version `echo $i | sed -e 's/\//./g' -e 's/\.class//g'` + # dump_version `echo $i | sed -e 's/^\.\///g' -e 's/\//./g' -e 's/\.class//g'` #done cd $TDIR } diff --git a/make/scripts/java-win32.bat b/make/scripts/java-win32.bat deleted file mode 100755 index 436d68b..0000000 --- a/make/scripts/java-win32.bat +++ /dev/null @@ -1,25 +0,0 @@ -
-set BLD_SUB=build-win32
-
-set J2RE_HOME=c:\jre-11.0.4+11_x32
-set JAVA_HOME=c:\jdk-11.0.4+11_x32
-set ANT_PATH=C:\apache-ant-1.10.5
-
-set BLD_DIR=..\%BLD_SUB%
-REM set LIB_DIR=..\%BLD_SUB%\obj;..\%BLD_SUB%\test\build\natives
-set LIB_DIR=..\%BLD_SUB%\test\build\natives
-
-set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw32\bin;%LIB_DIR%;%PATH%
-REM set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw32\bin;%PATH%
-
-set CP_ALL=.;lib\junit.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar;lib/semantic-versioning/semver.jar;%BLD_DIR%\gluegen-rt.jar;%BLD_DIR%\gluegen.jar;%BLD_DIR%\gluegen-test-util.jar;%BLD_DIR%\test\build\gluegen-test.jar
-
-echo CP_ALL %CP_ALL%
-
-set X_ARGS="-Drootrel.build=%BLD_SUB%" "-Dgluegen.root=.."
-REM set D_ARGS="-Djogamp.debug.Platform" "-Djogamp.debug.NativeLibrary"
-set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.IOUtil.Exe"
-REM set D_ARGS="-Djogamp.debug=all"
-
-%J2RE_HOME%\bin\java -classpath %CP_ALL% %X_ARGS% %D_ARGS% "-Djava.library.path=%LIB_DIR%" "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32.log 2>&1
-REM %J2RE_HOME%\bin\java -classpath %CP_ALL% %X_ARGS% %D_ARGS% "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32.log 2>&1
diff --git a/make/scripts/java-win64.bat b/make/scripts/java-win64.bat index 575d937..26a4591 100755 --- a/make/scripts/java-win64.bat +++ b/make/scripts/java-win64.bat @@ -1,16 +1,14 @@ set BLD_SUB=build-win64
-set J2RE_HOME=c:\jre-11.0.4+11_x64
-set JAVA_HOME=c:\jdk-11.0.4+11_x64
+set J2RE_HOME=c:\jdk-17
+set JAVA_HOME=c:\jdk-17
set ANT_PATH=C:\apache-ant-1.10.5
set BLD_DIR=..\%BLD_SUB%
-REM set LIB_DIR=..\%BLD_SUB%\obj;..\%BLD_SUB%\test\build\natives
-set LIB_DIR=..\%BLD_SUB%\test\build\natives
+set LIB_DIR=%cd%\..\%BLD_SUB%\test\build\natives
set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw64\bin;%LIB_DIR%;%PATH%
-REM set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw64\bin;%PATH%
set CP_ALL=.;lib\junit.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar;lib/semantic-versioning/semver.jar;lib\TestJarsInJar.jar;%BLD_DIR%\gluegen-rt.jar;%BLD_DIR%\gluegen.jar;%BLD_DIR%\gluegen-test-util.jar;%BLD_DIR%\test\build\gluegen-test.jar
@@ -18,6 +16,7 @@ echo CP_ALL %CP_ALL% set X_ARGS="-Drootrel.build=%BLD_SUB%" "-Dgluegen.root=.."
REM set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.JNILibLoader" "-Djogamp.debug.TempFileCache" "-Djogamp.debug.JarUtil" "-Djogamp.debug.TempJarCache"
+REM set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.NativeLibrary" "-Djogamp.debug.JNILibLoader" "-Djogamp.debug.TempFileCache" "-Djogamp.debug.JarUtil" "-Djogamp.debug.TempJarCache"
REM set D_ARGS="-Djogamp.debug.Platform" "-Djogamp.debug.NativeLibrary" "-Djogamp.debug.IOUtil"
REM set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.IOUtil.Exe" "-Djogamp.debug.IOUtil.Exe.NoStream"
REM set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.TempFileCache" "-Djogamp.debug.TempJarCache" "-Djogamp.debug.IOUtil.Exe" "-Djogamp.gluegen.UseNativeExeFile=true" "-Djava.io.tmpdir=c:\temp_noexec"
diff --git a/make/scripts/make.gluegen.all.ios.amd64.sh b/make/scripts/make.gluegen.all.ios.amd64.sh index bda783d..ddc0fd7 100755 --- a/make/scripts/make.gluegen.all.ios.amd64.sh +++ b/make/scripts/make.gluegen.all.ios.amd64.sh @@ -16,7 +16,7 @@ fi export SDKROOT=iphonesimulator13.2 xcrun --show-sdk-path -JAVA_HOME=`/usr/libexec/java_home -version 11` +JAVA_HOME=`/usr/libexec/java_home -version 17` PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME PATH which java diff --git a/make/scripts/make.gluegen.all.ios.arm64.sh b/make/scripts/make.gluegen.all.ios.arm64.sh index a4e811d..13c9469 100755 --- a/make/scripts/make.gluegen.all.ios.arm64.sh +++ b/make/scripts/make.gluegen.all.ios.arm64.sh @@ -16,7 +16,7 @@ fi export SDKROOT=iphoneos13.2 xcrun --show-sdk-path -JAVA_HOME=`/usr/libexec/java_home -version 11` +JAVA_HOME=`/usr/libexec/java_home -version 17` PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME PATH which java diff --git a/make/scripts/make.gluegen.all.linux-x86_64.sh b/make/scripts/make.gluegen.all.linux-x86_64.sh index b0bbed7..aaac667 100755 --- a/make/scripts/make.gluegen.all.linux-x86_64.sh +++ b/make/scripts/make.gluegen.all.linux-x86_64.sh @@ -2,6 +2,9 @@ SDIR=`dirname $0` +# export J2RE_HOME=/usr/lib/jvm/java-11-openjdk-amd64 +# export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 + if [ -e $SDIR/setenv-build-jogamp-x86_64.sh ] ; then . $SDIR/setenv-build-jogamp-x86_64.sh fi diff --git a/make/scripts/make.gluegen.all.macosx.sh b/make/scripts/make.gluegen.all.macosx.sh index d61843a..9d30807 100755 --- a/make/scripts/make.gluegen.all.macosx.sh +++ b/make/scripts/make.gluegen.all.macosx.sh @@ -13,7 +13,7 @@ fi # Force OSX SDK 10.6, if desired # export SDKROOT=macosx10.6 -JAVA_HOME=`/usr/libexec/java_home -version 11` +JAVA_HOME=`/usr/libexec/java_home -version 17` PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME PATH diff --git a/make/scripts/make.gluegen.all.win32.bat b/make/scripts/make.gluegen.all.win32.bat deleted file mode 100755 index caaf7f0..0000000 --- a/make/scripts/make.gluegen.all.win32.bat +++ /dev/null @@ -1,29 +0,0 @@ -set THISDIR="C:\JogAmp"
-
-set J2RE_HOME=c:\jre-11.0.4+11_x32
-set JAVA_HOME=c:\jdk-11.0.4+11_x32
-set ANT_PATH=C:\apache-ant-1.10.5
-set GIT_PATH=C:\cygwin64\bin
-set SEVENZIP=C:\Program Files\7-Zip
-
-set CMAKE_PATH=C:\cmake-3.15.2-win32-x86
-set CMAKE_C_COMPILER=c:\mingw32\bin\gcc
-
-set PATH=%J2RE_HOME%\bin;%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw32\bin;%CMAKE_PATH%\bin;%GIT_PATH%;%SEVENZIP%;%PATH%
-
-set LIB_GEN=%THISDIR%\lib
-set CLASSPATH=.;%THISDIR%\build-win32\classes
-REM -Dc.compiler.debug=true
-REM -DuseOpenMAX=true
-REM -DuseKD=true
-REM -Djogl.cg=1 -D-Dwindows.cg.lib=C:\Cg-2.2
-
-set SOURCE_LEVEL=1.8
-set TARGET_LEVEL=1.8
-set TARGET_RT_JAR=C:\jre1.8.0_212\lib\rt.jar
-
-REM set JOGAMP_JAR_CODEBASE=Codebase: *.jogamp.org
-set JOGAMP_JAR_CODEBASE=Codebase: *.goethel.localnet
-
-ant -Drootrel.build=build-win32 %1 %2 %3 %4 %5 %6 %7 %8 %9 > make.gluegen.all.win32.log 2>&1
-
diff --git a/make/scripts/make.gluegen.all.win64.bat b/make/scripts/make.gluegen.all.win64.bat index 239f8e2..b0dc64e 100755 --- a/make/scripts/make.gluegen.all.win64.bat +++ b/make/scripts/make.gluegen.all.win64.bat @@ -1,12 +1,12 @@ set THISDIR="C:\JogAmp"
-set J2RE_HOME=c:\jre-11.0.4+11_x64
-set JAVA_HOME=c:\jdk-11.0.4+11_x64
+set J2RE_HOME=c:\jdk-17
+set JAVA_HOME=c:\jdk-17
set ANT_PATH=C:\apache-ant-1.10.5
set GIT_PATH=C:\cygwin64\bin
set SEVENZIP=C:\Program Files\7-Zip
-set CMAKE_PATH=C:\cmake-3.15.2-win64-x64
+set CMAKE_PATH=C:\cmake-3.25.1-windows-x86_64
set CMAKE_C_COMPILER=c:\mingw64\bin\gcc
set PATH=%J2RE_HOME%\bin;%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw64\bin;%CMAKE_PATH%\bin;%GIT_PATH%;%SEVENZIP%;%PATH%
diff --git a/make/scripts/make.macosx.jdk_lipo_libs.sh b/make/scripts/make.macosx.jdk_lipo_libs.sh new file mode 100644 index 0000000..5619bc5 --- /dev/null +++ b/make/scripts/make.macosx.jdk_lipo_libs.sh @@ -0,0 +1,30 @@ +#! /bin/sh + +# +# First unpack the OpenJDK (Temurin) package +# for amd64 and arm64. +# Then copy each lib-folder 'temurin-xy.jdk/Contents/Home/lib/' +# to their respective target lib-folder: +# - temurin-xy.jdk.amd64.lib/ +# - temurin-xy.jdk.arm64.lib/ +# +# Now we can run this script producing fat lipo dylib files, +# placed into +# - temurin-xy.jdk.fat.lib +# + +amd64_dir=$HOME/temurin-17.jdk.amd64.lib +arm64_dir=$HOME/temurin-17.jdk.arm64.lib +fat_dir=$HOME/temurin-17.jdk.fat.lib + +rm -rf $fat_dir +mkdir $fat_dir + +for i in $amd64_dir/*.dylib ; do + bname=`basename $i` + if [ -e $arm64_dir/$bname ] ; then + lipo -create $i $arm64_dir/$bname -output $fat_dir/$bname + else + echo missing $arm64_dir/$bname + fi +done diff --git a/make/scripts/runtest-x32.bat b/make/scripts/runtest-x32.bat deleted file mode 100755 index 6f169d5..0000000 --- a/make/scripts/runtest-x32.bat +++ /dev/null @@ -1,16 +0,0 @@ -REM set TEMP=C:\Documents and Settings\jogamp\temp-exec -REM set TMP=C:\Documents and Settings\jogamp\temp-exec -REM set TEMP=C:\Users\jogamp\temp-exec -REM set TMP=C:\Users\jogamp\temp-exec - -REM scripts\java-win32.bat com.jogamp.common.GlueGenVersion -REM scripts\java-win32.bat com.jogamp.common.util.TestVersionInfo -REM scripts\java-win32.bat com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter -REM scripts\java-win32.bat com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter -REM scripts\java-win32.bat com.jogamp.common.util.TestTempJarCache -scripts\java-win32.bat com.jogamp.common.util.TestPlatform01 -REM scripts\java-win32.bat com.jogamp.common.os.TestElfReader01 -REM scripts\java-win32.bat com.jogamp.common.util.TestIOUtilURIHandling -REM scripts\java-win32.bat com.jogamp.common.nio.TestByteBufferInputStream -REM scripts\java-win32.bat com.jogamp.common.nio.TestByteBufferOutputStream - diff --git a/make/scripts/runtest-x64.bat b/make/scripts/runtest-x64.bat index 3507046..85f0d82 100755 --- a/make/scripts/runtest-x64.bat +++ b/make/scripts/runtest-x64.bat @@ -4,11 +4,11 @@ REM set TEMP=C:\Users\jogamp\temp-exec REM set TMP=C:\Users\jogamp\temp-exec REM scripts\java-win64.bat com.jogamp.common.GlueGenVersion -scripts\java-win64.bat com.jogamp.common.util.TestVersionInfo +REM scripts\java-win64.bat com.jogamp.common.util.TestVersionInfo REM scripts\java-win64.bat com.jogamp.gluegen.jcpp.IncludeAbsoluteTest -REM scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter +scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter REM scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter REM scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p2LoadJNIAndImplLib REM scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p2DynamicLibraryBundle diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh index 72279a6..4f40cd6 100755 --- a/make/scripts/runtest.sh +++ b/make/scripts/runtest.sh @@ -93,7 +93,7 @@ function onetest() { # #onetest com.jogamp.common.GlueGenVersion 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestSystemPropsAndEnvs 2>&1 | tee -a $LOG -onetest com.jogamp.common.util.TestVersionInfo 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestVersionInfo 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestVersionNumber 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestVersionSemantics 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestIteratorIndexCORE 2>&1 | tee -a $LOG @@ -148,7 +148,7 @@ onetest com.jogamp.common.util.TestVersionInfo 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.TokenPastingWhitespaceTest 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.jcpp.PreprocessorTest 2>&1 | tee -a $LOG -#onetest com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter 2>&1 | tee -a $LOG +onetest com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p2LoadJNIAndImplLib 2>&1 | tee -a $LOG #onetest com.jogamp.gluegen.test.junit.generation.Test1p2DynamicLibraryBundle 2>&1 | tee -a $LOG diff --git a/make/scripts/setenv-build-jogamp-x86.sh b/make/scripts/setenv-build-jogamp-x86.sh index 5c7ba06..c25474c 100644 --- a/make/scripts/setenv-build-jogamp-x86.sh +++ b/make/scripts/setenv-build-jogamp-x86.sh @@ -28,6 +28,16 @@ if [ ! -z "$J2RE_HOME" -a ! -z "$JAVA_HOME" ] ; then fi if [ -z "$FOUND_JAVA" ] ; then + if [ -e /usr/lib/jvm/java-17-openjdk-i386 ] ; then + J2RE_HOME=/usr/lib/jvm/java-17-openjdk-i386 + JAVA_HOME=/usr/lib/jvm/java-17-openjdk-i386 + PATH=$JAVA_HOME/bin:$PATH + export J2RE_HOME JAVA_HOME + FOUND_JAVA=1 + fi +fi + +if [ -z "$FOUND_JAVA" ] ; then if [ -e /usr/lib/jvm/java-11-openjdk-i386 ] ; then J2RE_HOME=/usr/lib/jvm/java-11-openjdk-i386 JAVA_HOME=/usr/lib/jvm/java-11-openjdk-i386 diff --git a/make/scripts/setenv-build-jogamp-x86_64.sh b/make/scripts/setenv-build-jogamp-x86_64.sh index e9bf313..26dc5d0 100644 --- a/make/scripts/setenv-build-jogamp-x86_64.sh +++ b/make/scripts/setenv-build-jogamp-x86_64.sh @@ -28,6 +28,16 @@ if [ ! -z "$J2RE_HOME" -a ! -z "$JAVA_HOME" ] ; then fi if [ -z "$FOUND_JAVA" ] ; then + if [ -e /usr/lib/jvm/java-17-openjdk-amd64 ] ; then + J2RE_HOME=/usr/lib/jvm/java-17-openjdk-amd64 + JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 + PATH=$JAVA_HOME/bin:$PATH + export J2RE_HOME JAVA_HOME + FOUND_JAVA=1 + fi +fi + +if [ -z "$FOUND_JAVA" ] ; then if [ -e /usr/lib/jvm/java-11-openjdk-amd64 ] ; then J2RE_HOME=/usr/lib/jvm/java-11-openjdk-amd64 JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 diff --git a/make/scripts/test-win32-smb_share.bat b/make/scripts/test-win32-smb_share.bat deleted file mode 100755 index ce1ab1f..0000000 --- a/make/scripts/test-win32-smb_share.bat +++ /dev/null @@ -1,24 +0,0 @@ -
-set SMB_ROOT=\\risa.goethel.localnet\deployment\test\jogamp
-
-set BLD_SUB=build-win32
-set J2RE_HOME=c:\jre8u202-b08_x32
-set JAVA_HOME=c:\jdk8u202-b08_x32
-set ANT_PATH=C:\apache-ant-1.9.4
-
-set PROJECT_ROOT=%SMB_ROOT%\gluegen
-set BLD_DIR=%PROJECT_ROOT%\%BLD_SUB%
-
-set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;%PATH%
-
-set D_ARGS="-Djogamp.debug=all"
-
-set LIB_DIR=
-
-set CP_ALL=.;%BLD_DIR%\gluegen-rt.jar;%PROJECT_ROOT%\make\lib\junit.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar
-
-echo CP_ALL %CP_ALL%
-
-%J2RE_HOME%\bin\java -classpath %CP_ALL% %D_ARGS% %X_ARGS% com.jogamp.common.GlueGenVersion > java-win.log 2>&1
-tail java-win.log
-
diff --git a/src/java/com/jogamp/common/av/AudioFormat.java b/src/java/com/jogamp/common/av/AudioFormat.java new file mode 100644 index 0000000..2802f31 --- /dev/null +++ b/src/java/com/jogamp/common/av/AudioFormat.java @@ -0,0 +1,193 @@ +/** + * Copyright 2013-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.common.av; + +/** + * Specifies the linear audio PCM format. + */ +public class AudioFormat { + /** + * @param sampleRate sample rate in Hz (1/s), e.g. 44100 Hz + * @param sampleSize sample size in bits, e.g. 16 bits + * @param channelCount number of channels, e.g. 2 channels for stereo + * @param signed true if signed PCM values, false for unsigned values + * @param fixedP true for fixed point values, false for unsigned floating point values with a sampleSize of 32 (float) or 64 (double) + * @param planar true for planar data package (each channel in own data buffer), false for packed data channels interleaved in one buffer. + * @param littleEndian true for little-endian byte order, false for big endian byte order + */ + public AudioFormat(final int sampleRate, final int sampleSize, final int channelCount, final boolean signed, final boolean fixedP, final boolean planar, final boolean littleEndian) { + this.sampleRate = sampleRate; + this.sampleSize = sampleSize; + this.channelCount = channelCount; + this.signed = signed; + this.fixedP = fixedP; + this.planar = planar; + this.littleEndian = littleEndian; + if( !fixedP ) { + if( sampleSize != 32 && sampleSize != 64 ) { + throw new IllegalArgumentException("Floating point: sampleSize "+sampleSize+" bits"); + } + if( !signed ) { + throw new IllegalArgumentException("Floating point: unsigned"); + } + } + } + + /** Sample rate in Hz (1/s, e.g. 44100 Hz. */ + public final int sampleRate; + /** Sample size in bits, e.g. 16 bits. */ + public final int sampleSize; + /** Number of channels, e.g. 2 channels for stereo. */ + public final int channelCount; + /** Signed PCM values if true, otherwise unsigned values. */ + public final boolean signed; + /** Fixed or floating point values. Floating point 'float' has {@link #sampleSize} 32, 'double' has {@link #sampleSize} 64. */ + public final boolean fixedP; + /** Planar or packed samples. If planar, each channel has their own data buffer. If packed, channel data is interleaved in one buffer. */ + public final boolean planar; + /** Little-endian byte order if true, otherwise big endian byte order. */ + public final boolean littleEndian; + + + // + // Time <-> Bytes + // + + /** + * Returns the byte size of the given duration in seconds + * according to {@link #sampleSize}, {@link #channelCount} and {@link #sampleRate}. + * <pre> + * final float bytesPerSample = sampleSize/8; + * return Math.round( duration * channelCount * bytesPerSample * sampleRate ); + * </pre> + * <p> + * Time -> Byte Count + * </p> + * @param duration duration in seconds + */ + public final int getDurationsByteSize(final float duration) { + final float bytesPerSample = sampleSize >>> 3; // /8 + return Math.round( duration * channelCount * bytesPerSample * sampleRate ); + } + + /** + * Returns the duration in seconds of the given byte count + * according to {@link #sampleSize}, {@link #channelCount} and {@link #sampleRate}. + * <pre> + * final float bytesPerSample = sampleSize/8; + * return byteCount / ( channelCount * bytesPerSample * sampleRate ) + * </pre> + * <p> + * Byte Count -> Time + * </p> + * @param byteCount size in bytes + */ + public final float getBytesDuration(final int byteCount) { + final float bytesPerSample = sampleSize >>> 3; // /8 + return byteCount / ( channelCount * bytesPerSample * sampleRate ); + } + + /** + * Returns the duration in seconds of the given sample count per frame and channel + * according to the {@link #sampleRate}, i.e. + * <pre> + * (float)sampleCount / sampleRate + * </pre> + * <p> + * Sample Count -> Time + * </p> + * @param sampleCount sample count per frame and channel + */ + public final float getSamplesDuration(final int sampleCount) { + return (float)sampleCount / sampleRate; + } + + /** + * Returns the rounded frame count of the given duration and frame duration, both in seconds. + * <pre> + * Math.max(1, Math.round( duration / frameDuration )) + * </pre> + * <p> + * Note: <code>frameDuration</code> can be derived by <i>sample count per frame and channel</i> + * via {@link #getSamplesDuration(int)} or by <i>byte count</i> via {@link #getBytesDuration(int)}. + * </p> + * <p> + * Frame Time -> Frame Count + * </p> + * @param duration duration in seconds + * @param frameDuration duration per frame in seconds, i.e. 1/frame_rate + * @see #getSamplesDuration(int) + * @see #getBytesDuration(int) + */ + public final int getFrameCount(final float duration, final float frameDuration) { + return Math.max(1, Math.round( duration / frameDuration )); + } + + /** + * Returns the byte size of given sample count + * according to the {@link #sampleSize}, i.e.: + * <pre> + * sampleCount * ( sampleSize / 8 ) + * </pre> + * <p> + * Note: To retrieve the byte size for all channels, + * you need to pre-multiply <code>sampleCount</code> with {@link #channelCount}. + * </p> + * <p> + * Sample Count -> Byte Count + * </p> + * @param sampleCount sample count + */ + public final int getSamplesByteCount(final int sampleCount) { + return sampleCount * ( sampleSize >>> 3 ); + } + + /** + * Returns the sample count of given byte count + * according to the {@link #sampleSize}, i.e.: + * <pre> + * ( byteCount * 8 ) / sampleSize + * </pre> + * <p> + * Note: If <code>byteCount</code> covers all channels and you request the sample size per channel, + * you need to divide the result by <code>sampleCount</code> by {@link #channelCount}. + * </p> + * <p> + * Byte Count -> Sample Count + * </p> + * @param byteCount number of bytes + */ + public final int getBytesSampleCount(final int byteCount) { + return ( byteCount << 3 ) / sampleSize; + } + + @Override + public String toString() { + return "AudioFormat[sampleRate "+sampleRate+", sampleSize "+sampleSize+", channelCount "+channelCount+ + ", signed "+signed+", fixedP "+fixedP+", "+(planar?"planar":"packed")+", "+(littleEndian?"little":"big")+"-endian]"; } +}
\ No newline at end of file diff --git a/src/java/com/jogamp/common/av/AudioSink.java b/src/java/com/jogamp/common/av/AudioSink.java new file mode 100644 index 0000000..ac6441a --- /dev/null +++ b/src/java/com/jogamp/common/av/AudioSink.java @@ -0,0 +1,444 @@ +/** + * Copyright 2013-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.common.av; + +import java.nio.ByteBuffer; + +import jogamp.common.Debug; + +public interface AudioSink { + public static final boolean DEBUG = Debug.debug("AudioSink"); + + /** Default frame duration in millisecond, i.e. 1 {@link AudioFrame} per {@value} ms. */ + public static final int DefaultFrameDuration = 32; + + /** Initial audio queue size in milliseconds. {@value} ms, i.e. 16 {@link AudioFrame}s per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/ + public static final int DefaultInitialQueueSize = 16 * 32; // 512 ms + /** Audio queue grow size in milliseconds. {@value} ms, i.e. 16 {@link AudioFrame}s per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/ + public static final int DefaultQueueGrowAmount = 16 * 32; // 512 ms + /** Audio queue limit w/ video in milliseconds. {@value} ms, i.e. 96 {@link AudioFrame}s per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/ + public static final int DefaultQueueLimitWithVideo = 96 * 32; // 3072 ms + /** Audio queue limit w/o video in milliseconds. {@value} ms, i.e. 32 {@link AudioFrame}s per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/ + public static final int DefaultQueueLimitAudioOnly = 32 * 32; // 1024 ms + + /** Default {@link AudioFormat}, [type PCM, sampleRate 44100, sampleSize 16, channelCount 2, signed, fixedP, !planar, littleEndian]. */ + public static final AudioFormat DefaultFormat = new AudioFormat(44100, 16, 2, true /* signed */, + true /* fixed point */, false /* planar */, true /* littleEndian */); + + /** + * Abstract audio frame containing multiple audio samples per channel, tracking {@link TimeFrameI} pts and size in bytes. + * <p> + * One {@link AudioFrame} may contain multiple pairs of samples per channel, + * i.e. this {@link AudioFrame} does not limit a frame to be one sample per channel. + * See its application in {@link AudioSink#enqueueData(int, ByteBuffer, int)}. + * </p> + * <p> + * Implementations may assign actual data to queue frames from streaming, see {@link AudioDataFrame}. + * </p> + * @see AudioSink#enqueueData(int, ByteBuffer, int) + */ + public static abstract class AudioFrame extends TimeFrameI { + protected int byteSize; + + /** + * Ctor w/ zero duration, {@link #INVALID_PTS} and zero byte size + */ + public AudioFrame() { + this.byteSize = 0; + } + /** + * Create a new instance + * @param pts frame pts in milliseconds + * @param duration frame duration in milliseconds + * @param byteCount size in bytes + */ + public AudioFrame(final int pts, final int duration, final int byteCount) { + super(pts, duration); + this.byteSize=byteCount; + } + + /** Get this frame's size in bytes. */ + public final int getByteSize() { return byteSize; } + /** Set this frame's size in bytes. */ + public final void setByteSize(final int size) { this.byteSize=size; } + + @Override + public String toString() { + return "AudioFrame[pts " + pts + " ms, l " + duration + " ms, "+byteSize + " bytes]"; + } + } + /** + * Audio data frame example of {@link AudioFrame} with actual audio data being attached. + */ + public static class AudioDataFrame extends AudioFrame { + protected final ByteBuffer data; + + /** + * Create a new instance + * @param pts frame pts in milliseconds + * @param duration frame duration in milliseconds + * @param bytes audio data + * @param byteCount size in bytes + */ + public AudioDataFrame(final int pts, final int duration, final ByteBuffer bytes, final int byteCount) { + super(pts, duration, byteCount); + if( byteCount > bytes.remaining() ) { + throw new IllegalArgumentException("Give size "+byteCount+" exceeds remaining bytes in ls "+bytes+". "+this); + } + this.data=bytes; + } + + /** Get this frame's data. */ + public final ByteBuffer getData() { return data; } + + @Override + public String toString() { + return "AudioDataFrame[pts " + pts + " ms, l " + duration + " ms, "+byteSize + " bytes, " + data + "]"; + } + } + + /** + * Makes the audio context current on the calling thread, if implementation utilizes context locking. + * <p> + * If implementation doesn't utilizes context locking, method always returns true. + * </p> + * <p> + * Recursive call to {@link #makeCurrent()} and hence {@link #release()} are supported. + * </p> + * <p> + * At any point in time one context can only be current by one thread, + * and one thread can only have one context current. + * </p> + * @param throwException if true, throws ALException if context is null, current thread holds another context or failed to natively make current + * @return true if current thread holds no other context and context successfully made current, otherwise false + * @see #release() + */ + public boolean makeCurrent(final boolean throwException); + + /** + * Releases control of this audio context from the current thread, if implementation utilizes context locking. + * <p> + * If implementation doesn't utilizes context locking, method always returns true. + * </p> + * <p> + * Recursive call to {@link #makeCurrent()} and hence {@link #release()} are supported. + * </p> + * @param throwException if true, throws ALException if context has not been previously made current on current thread + * or native release failed. + * @return true if context has previously been made current on the current thread and successfully released, otherwise false + * @see #makeCurrent() + */ + public boolean release(final boolean throwException); + + /** + * Returns the <code>available state</code> of this instance. + * <p> + * The <code>available state</code> is affected by this instance + * overall availability, i.e. after instantiation, + * as well as by {@link #destroy()}. + * </p> + */ + public boolean isAvailable(); + + /** Returns the playback speed. */ + public float getPlaySpeed(); + + /** + * Sets the playback speed. + * <p> + * To simplify test, play speed is <i>normalized</i>, i.e. + * <ul> + * <li><code>1.0f</code>: if <code> Math.abs(1.0f - rate) < 0.01f </code></li> + * </ul> + * </p> + * @return true if successful, otherwise false, i.e. due to unsupported value range of implementation. + */ + public boolean setPlaySpeed(float s); + + /** Returns the volume. */ + public float getVolume(); + + /** + * Sets the volume [0f..1f]. + * <p> + * To simplify test, volume is <i>normalized</i>, i.e. + * <ul> + * <li><code>0.0f</code>: if <code> Math.abs(v) < 0.01f </code></li> + * <li><code>1.0f</code>: if <code> Math.abs(1.0f - v) < 0.01f </code></li> + * </ul> + * </p> + * @return true if successful, otherwise false, i.e. due to unsupported value range of implementation. + */ + public boolean setVolume(float v); + + /** + * Returns the number of sources the used device is capable to mix. + * <p> + * This device attribute is only formally exposed and not used, + * since an audio sink is only utilizing one source. + * </p> + * <p> + * May return <code>-1</code> if undefined. + * </p> + * @return + */ + public int getSourceCount(); + + /** + * Returns the default (minimum) latency in seconds + * <p> + * Latency might be the reciprocal mixer-refresh-interval [Hz], e.g. 50 Hz refresh-rate = 20ms minimum latency. + * </p> + * <p> + * May return 20ms for a 50 Hz refresh rate if undefined. + * </p> + */ + public float getDefaultLatency(); + + /** + * Returns the native {@link AudioFormat} by this sink. + * <p> + * The native format is guaranteed to be supported + * and shall reflect this sinks most native format, + * i.e. best performance w/o data conversion. + * </p> + * <p> + * The native format is not impacted by {@link #setChannelLimit(int)}. + * </p> + * <p> + * May return {@link AudioSink#DefaultFormat} if undefined. + * </p> + * @see #init(AudioFormat, float, int, int, int) + */ + public AudioFormat getNativeFormat(); + + /** + * Returns the preferred {@link AudioFormat} by this sink. + * <p> + * The preferred format is a subset of {@link #getNativeFormat()}, + * impacted by {@link #setChannelLimit(int)}. + * </p> + * <p> + * Known {@link #AudioFormat} attributes considered by implementations: + * <ul> + * <li>ALAudioSink: {@link AudioFormat#sampleRate}. + * <li>ALAudioSink: {@link AudioFormat#channelCount} + * </ul> + * </p> + * @see #getNativeFormat() + * @see #init(AudioFormat, float, int, int, int) + * @see #setChannelLimit(int) + * @see #isSupported(AudioFormat) + */ + public AudioFormat getPreferredFormat(); + + /** + * Limit maximum supported audio channels by user. + * <p> + * Must be set before {@link #getPreferredFormat()}, {@link #isSupported(AudioFormat)} and naturally {@link #init(AudioFormat, int, int, int, int)}. + * </p> + * <p> + * May be utilized to enforce 1 channel (mono) downsampling + * in combination with JOAL/OpenAL to experience spatial 3D position effects. + * </p> + * @param cc maximum supported audio channels, will be clipped [1..{@link #getNativeFormat()}.{@link AudioFormat#channelCount channelCount}] + * @see #getNativeFormat() + * @see #getPreferredFormat() + * @see #isSupported(AudioFormat) + * @see #init(AudioFormat, int, int, int, int) + */ + public void setChannelLimit(final int cc); + + /** + * Returns true if the given format is supported by the sink, otherwise false. + * <p> + * The {@link #getPreferredFormat()} is used to validate compatibility with the given format. + * </p> + * @see #init(AudioFormat, float, int, int, int) + * @see #getPreferredFormat() + */ + public boolean isSupported(AudioFormat format); + + /** + * Initializes the sink. + * <p> + * Implementation must match the given <code>requestedFormat</code> {@link AudioFormat}. + * </p> + * <p> + * Caller shall validate <code>requestedFormat</code> via {@link #isSupported(AudioFormat)} + * beforehand and try to find a suitable supported one. + * {@link #getPreferredFormat()} may help. + * </p> + * @param requestedFormat the requested {@link AudioFormat}. + * @param frameDurationHint average {@link AudioFrame} duration hint in milliseconds. + * May assist to shape the {@link AudioFrame} initial queue size using `initialQueueSize`. + * May assist to adjust latency of the backend, as currently used for JOAL's ALAudioSink. + * A value below 30ms or {@link #DefaultFrameDuration} may increase the audio processing load. + * Assumed as {@link #DefaultFrameDuration}, if <code>frameDuration < 1 ms</code>. + * @param initialQueueSize initial queue size in milliseconds, see {@link #DefaultInitialQueueSize}. + * May use `frameDurationHint` to determine initial {@link AudioFrame} queue size. + * @param queueGrowAmount queue grow size in milliseconds if queue is full, see {@link #DefaultQueueGrowAmount}. + * May use {@link #getAvgFrameDuration()} to determine {@link AudioFrame} queue growth amount. + * @param queueLimit maximum time in milliseconds the queue can hold (and grow), see {@link #DefaultQueueLimitWithVideo} and {@link #DefaultQueueLimitAudioOnly}. + * May use {@link #getAvgFrameDuration()} to determine {@link AudioFrame} queue limit. + * @return true if successful, otherwise false + * @see #enqueueData(int, ByteBuffer, int) + * @see #getAvgFrameDuration() + */ + public boolean init(AudioFormat requestedFormat, int frameDurationHint, + int initialQueueSize, int queueGrowAmount, int queueLimit); + + /** + * Returns the {@link AudioFormat} as chosen by {@link #init(AudioFormat, float, int, int, int)}, + * i.e. it shall match the <i>requestedFormat</i>. + */ + public AudioFormat getChosenFormat(); + + /** + * Returns the (minimum) latency in seconds of this sink as set by {@link #init(AudioFormat, float, int, int, int)}, see {@link #getDefaultLatency()}. + * <p> + * Latency might be the reciprocal mixer-refresh-interval [Hz], e.g. 50 Hz refresh-rate = 20ms minimum latency. + * </p> + * @see #init(AudioFormat, float, int, int, int) + */ + public float getLatency(); + + /** + * Returns true, if {@link #play()} has been requested <i>and</i> the sink is still playing, + * otherwise false. + */ + public boolean isPlaying(); + + /** + * Play buffers queued via {@link #enqueueData(AudioFrame)} from current internal position. + * If no buffers are yet queued or the queue runs empty, playback is being continued when buffers are enqueued later on. + * @see #enqueueData(AudioFrame) + * @see #pause() + */ + public void play(); + + /** + * Pause playing buffers while keeping enqueued data incl. it's internal position. + * @see #play() + * @see #flush() + * @see #enqueueData(AudioFrame) + */ + public void pause(); + + /** + * Flush all queued buffers, implies {@link #pause()}. + * <p> + * {@link #init(AudioFormat, float, int, int, int)} must be called first. + * </p> + * @see #play() + * @see #pause() + * @see #enqueueData(AudioFrame) + * @see #init(AudioFormat, float, int, int, int) + */ + public void flush(); + + /** Destroys this instance, i.e. closes all streams and devices allocated. */ + public void destroy(); + + /** + * Returns the number of allocated buffers as requested by + * {@link #init(AudioFormat, float, int, int, int)}. + * @see #init(AudioFormat, float, int, int, int) + */ + public int getFrameCount(); + + /** + * Returns the current enqueued frames count since {@link #init(AudioFormat, float, int, int, int)}. + * @see #init(AudioFormat, float, int, int, int) + */ + public int getEnqueuedFrameCount(); + + /** + * Returns the current number of frames queued for playing. + * <p> + * {@link #init(AudioFormat, float, int, int, int)} must be called first. + * </p> + * @see #init(AudioFormat, float, int, int, int) + */ + public int getQueuedFrameCount(); + + /** + * Returns the current number of bytes queued for playing. + * <p> + * {@link #init(AudioFormat, float, int, int, int)} must be called first. + * </p> + * @see #init(AudioFormat, float, int, int, int) + */ + public int getQueuedByteCount(); + + /** + * Returns the current queued frame time in seconds for playing. + * <p> + * {@link #init(AudioFormat, float, int, int, int)} must be called first. + * </p> + * @see #init(AudioFormat, float, int, int, int) + */ + public float getQueuedTime(); + + /** + * Returns average frame duration last assessed @ {@link #enqueueData(int, ByteBuffer, int)} when queue was full. + * <pre> + * avgFrameDuration = {@link #getQueuedTime()} / {@link #getQueuedFrameCount()} + * </pre> + */ + public float getAvgFrameDuration(); + + /** + * Return the current audio presentation timestamp (PTS) in milliseconds. + */ + public int getPTS(); + + /** + * Returns the current number of frames in the sink available for writing. + * <p> + * {@link #init(AudioFormat, float, int, int, int)} must be called first. + * </p> + * @see #init(AudioFormat, float, int, int, int) + */ + public int getFreeFrameCount(); + + /** + * Enqueue <code>byteCount</code> bytes as a new {@link AudioFrame} to this sink. + * <p> + * The data must comply with the chosen {@link AudioFormat} as set via {@link #init(AudioFormat, float, int, int, int)}. + * </p> + * <p> + * {@link #init(AudioFormat, float, int, int, int)} must be called first. + * </p> + * @param pts presentation time stamp in milliseconds for the newly enqueued {@link AudioFrame} + * @param bytes audio data for the newly enqueued {@link AudioFrame} + * @returns the enqueued internal {@link AudioFrame}. + * @see #init(AudioFormat, float, int, int, int) + */ + public AudioFrame enqueueData(int pts, ByteBuffer bytes, int byteCount); +} diff --git a/src/java/com/jogamp/common/av/AudioSinkFactory.java b/src/java/com/jogamp/common/av/AudioSinkFactory.java new file mode 100644 index 0000000..f4a320b --- /dev/null +++ b/src/java/com/jogamp/common/av/AudioSinkFactory.java @@ -0,0 +1,69 @@ +/** + * Copyright 2013-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.common.av; + +import com.jogamp.common.util.ReflectionUtil; + +import jogamp.common.av.NullAudioSink; + +public class AudioSinkFactory { + private static final String ALAudioSinkClazzName = "com.jogamp.openal.util.ALAudioSink"; + private static final String JavaAudioSinkClazzName = "jogamp.common.av.JavaSoundAudioSink"; + + public static AudioSink createDefault(final ClassLoader cl) { + AudioSink sink = create(cl, ALAudioSinkClazzName); + if( null == sink ) { + sink = create(cl, JavaAudioSinkClazzName); + } + if( null == sink ) { + sink = createNull(); + } + return sink; + } + public static AudioSink createNull() { + return new NullAudioSink(); + } + + public static AudioSink create(final ClassLoader cl, final String implName) { + final AudioSink audioSink; + if(ReflectionUtil.isClassAvailable(implName, cl)){ + try { + audioSink = (AudioSink) ReflectionUtil.createInstance(implName, cl); + if( audioSink.isAvailable() ) { + return audioSink; + } else if(AudioSink.DEBUG) { + System.err.println("AudioSinkFactory: Couldn't instantiate AudioSink '"+implName+"'"); + } + } catch (final Throwable t) { + if(AudioSink.DEBUG) { System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage()); t.printStackTrace(); } + } + } + return null; + } + +} diff --git a/src/java/com/jogamp/common/av/TimeFrameI.java b/src/java/com/jogamp/common/av/TimeFrameI.java new file mode 100644 index 0000000..400618f --- /dev/null +++ b/src/java/com/jogamp/common/av/TimeFrameI.java @@ -0,0 +1,89 @@ +/** + * Copyright 2013-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.common.av; + +/** + * Integer time frame in milliseconds, maybe specialized for texture/video, audio, .. animated content. + * <p> + * Type and value range has been chosen to suit embedded CPUs + * and characteristics of audio / video streaming and animations. + * Milliseconds of type integer with a maximum value of {@link Integer#MAX_VALUE} + * will allow tracking time up 2,147,483.647 seconds or + * 24 days 20 hours 31 minutes and 23 seconds. + * </p> + * <p> + * Milliseconds granularity is also more than enough to deal with A-V synchronization, + * where the threshold usually lies within 22ms. + * </p> + * <p> + * Milliseconds granularity for displaying video frames might seem inaccurate + * for each single frame, i.e. 60Hz != 16ms, however, accumulated values diminish + * this error and vertical sync is achieved by build-in V-Sync of the video drivers. + * </p> + */ +public class TimeFrameI { + /** Constant marking an invalid PTS, i.e. Integer.MIN_VALUE == 0x80000000 == {@value}. Sync w/ native code. */ + public static final int INVALID_PTS = 0x80000000; + + /** Constant marking the end of the stream PTS, i.e. Integer.MIN_VALUE - 1 == 0x7FFFFFFF == {@value}. Sync w/ native code. */ + public static final int END_OF_STREAM_PTS = 0x7FFFFFFF; + + protected int pts; + protected int duration; + + /** + * Ctor w/ zero duration and {@link #INVALID_PTS}. + */ + public TimeFrameI() { + pts = INVALID_PTS; + duration = 0; + } + /** + * Create a new instance + * @param pts frame pts in milliseconds + * @param duration frame duration in milliseconds + */ + public TimeFrameI(final int pts, final int duration) { + this.pts = pts; + this.duration = duration; + } + + /** Get this frame's presentation timestamp (PTS) in milliseconds. */ + public final int getPTS() { return pts; } + /** Set this frame's presentation timestamp (PTS) in milliseconds. */ + public final void setPTS(final int pts) { this.pts = pts; } + /** Get this frame's duration in milliseconds. */ + public final int getDuration() { return duration; } + /** Set this frame's duration in milliseconds. */ + public final void setDuration(final int duration) { this.duration = duration; } + + @Override + public String toString() { + return "TimeFrame[pts " + pts + " ms, l " + duration + " ms]"; + } +} diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java index eee65d8..cccea1a 100644 --- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java +++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java @@ -44,7 +44,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.HashSet; @@ -56,6 +55,7 @@ import com.jogamp.common.net.Uri; import com.jogamp.common.os.NativeLibrary; import com.jogamp.common.util.JarUtil; import com.jogamp.common.util.PropertyAccess; +import com.jogamp.common.util.SecurityUtil; import com.jogamp.common.util.cache.TempJarCache; import jogamp.common.Debug; @@ -512,7 +512,7 @@ public class JNILibLoaderBase { final String sunAppletLauncherProperty = "sun.jnlp.applet.launcher"; final String sunAppletLauncherClassName = "org.jdesktop.applet.util.JNLPAppletLauncher"; - final Method loadLibraryMethod = AccessController.doPrivileged(new PrivilegedAction<Method>() { + final Method loadLibraryMethod = SecurityUtil.doPrivileged(new PrivilegedAction<Method>() { @Override public Method run() { // FIXME: remove @@ -605,14 +605,14 @@ public class JNILibLoaderBase { mode = 2; } else { if(DEBUG) { - System.err.println("JNILibLoaderBase: System.loadLibrary("+libraryName+") - mode 3"); + System.err.println("JNILibLoaderBase: System.loadLibrary("+libraryName+") - mode 3: SystemEnvLibraryPaths: "+NativeLibrary.getSystemEnvLibraryPaths()); } try { System.loadLibrary(libraryName); mode = 3; } catch (final UnsatisfiedLinkError ex1) { if(DEBUG) { - System.err.println("ERROR (retry w/ enumLibPath) - "+ex1.getMessage()); + System.err.println("ERROR mode 3 - "+ex1.getMessage()); } final List<String> possiblePaths = NativeLibrary.enumerateLibraryPaths(libraryName, libraryName, libraryName, cl); // Iterate down these and see which one if any we can actually find. @@ -629,7 +629,10 @@ public class JNILibLoaderBase { System.err.println("n/a - "+ex2.getMessage()); } if(!iter.hasNext()) { - throw ex2; + // Avoid misleading final exception, use our own + throw new UnsatisfiedLinkError("Couldn't load library '"+libraryName+ + "' generically including "+NativeLibrary.getSystemEnvLibraryPaths()+ // mode 3 + ", nor as "+possiblePaths); // mode 4 } } } diff --git a/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java b/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java index 185142f..9b39657 100644 --- a/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java +++ b/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java @@ -3,11 +3,12 @@ package com.jogamp.common.net; import java.net.URL; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; +import com.jogamp.common.util.SecurityUtil; + public class GenericURLStreamHandlerFactory implements URLStreamHandlerFactory { private static GenericURLStreamHandlerFactory factory = null; @@ -48,7 +49,7 @@ public class GenericURLStreamHandlerFactory implements URLStreamHandlerFactory { */ public synchronized static GenericURLStreamHandlerFactory register() { if(null == factory) { - factory = AccessController.doPrivileged(new PrivilegedAction<GenericURLStreamHandlerFactory>() { + factory = SecurityUtil.doPrivileged(new PrivilegedAction<GenericURLStreamHandlerFactory>() { @Override public GenericURLStreamHandlerFactory run() { boolean ok = false; diff --git a/src/java/com/jogamp/common/nio/Buffers.java b/src/java/com/jogamp/common/nio/Buffers.java index 875163e..f37eaa9 100644 --- a/src/java/com/jogamp/common/nio/Buffers.java +++ b/src/java/com/jogamp/common/nio/Buffers.java @@ -50,11 +50,11 @@ import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.nio.ShortBuffer; -import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.SecurityUtil; import com.jogamp.common.util.UnsafeUtil; import com.jogamp.common.util.ValueConv; @@ -818,6 +818,156 @@ public class Buffers { } @SuppressWarnings("unchecked") + public static <B extends Buffer> B put3b(final B dest, final byte v1, final byte v2, final byte v3) { + if (dest instanceof ByteBuffer) { + final ByteBuffer b = (ByteBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof ShortBuffer) { + final ShortBuffer b = (ShortBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof CharBuffer) { + final CharBuffer b = (CharBuffer) dest; + b.put((char)v1); + b.put((char)v2); + b.put((char)v3); + return (B)b; + } else { + throw new IllegalArgumentException("Byte doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B put4b(final B dest, final byte v1, final byte v2, final byte v3, final byte v4) { + if (dest instanceof ByteBuffer) { + final ByteBuffer b = (ByteBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof ShortBuffer) { + final ShortBuffer b = (ShortBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof CharBuffer) { + final CharBuffer b = (CharBuffer) dest; + b.put((char)v1); + b.put((char)v2); + b.put((char)v3); + b.put((char)v4); + return (B)b; + } else { + throw new IllegalArgumentException("Byte doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B putb(final B dest, final byte[] src, final int offset, final int length) { + if (dest instanceof ByteBuffer) { + return (B) ((ByteBuffer) dest).put(src, offset, length); + } else if (dest instanceof ShortBuffer) { + final ShortBuffer b = (ShortBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof CharBuffer) { + final CharBuffer b = (CharBuffer) dest; + for(int i=0; i<length; ++i) { + b.put((char) src[offset+i]); + } + return (B)b; + } else { + throw new IllegalArgumentException("Byte doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") public static <B extends Buffer> B puts(final B dest, final short v) { if (dest instanceof ShortBuffer) { return (B) ((ShortBuffer) dest).put(v); @@ -835,6 +985,118 @@ public class Buffers { } @SuppressWarnings("unchecked") + public static <B extends Buffer> B put3s(final B dest, final short v1, final short v2, final short v3) { + if (dest instanceof ShortBuffer) { + final ShortBuffer b = (ShortBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else { + throw new IllegalArgumentException("Short doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B put4s(final B dest, final short v1, final short v2, final short v3, final short v4) { + if (dest instanceof ShortBuffer) { + final ShortBuffer b = (ShortBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else { + throw new IllegalArgumentException("Short doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B puts(final B dest, final short[] src, final int offset, final int length) { + if (dest instanceof ShortBuffer) { + return (B) ((ShortBuffer) dest).put(src, offset, length); + } else if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else { + throw new IllegalArgumentException("Short doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") public static <B extends Buffer> B puti(final B dest, final int v) { if (dest instanceof IntBuffer) { return (B) ((IntBuffer) dest).put(v); @@ -850,6 +1112,99 @@ public class Buffers { } @SuppressWarnings("unchecked") + public static <B extends Buffer> B put3i(final B dest, final int v1, final int v2, final int v3) { + if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else { + throw new IllegalArgumentException("Integer doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B put4i(final B dest, final int v1, final int v2, final int v3, final int v4) { + if (dest instanceof IntBuffer) { + final IntBuffer b = (IntBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else { + throw new IllegalArgumentException("Integer doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B puti(final B dest, final int[] src, final int offset, final int length) { + if (dest instanceof IntBuffer) { + return (B) ((IntBuffer) dest).put(src, offset, length); + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof LongBuffer) { + final LongBuffer b = (LongBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else { + throw new IllegalArgumentException("Integer doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") public static <B extends Buffer> B putf(final B dest, final float v) { if (dest instanceof FloatBuffer) { return (B) ((FloatBuffer) dest).put(v); @@ -865,14 +1220,126 @@ public class Buffers { } @SuppressWarnings("unchecked") - public static <B extends Buffer> B putd(final B dest, final double v) { + public static <B extends Buffer> B put3f(final B dest, final float v1, final float v2, final float v3) { + if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else { + throw new IllegalArgumentException("Float doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B put4f(final B dest, final float v1, final float v2, final float v3, final float v4) { if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else { + throw new IllegalArgumentException("Float doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B putf(final B dest, final float[] src, final int offset, final int length) { + if (dest instanceof FloatBuffer) { + return (B) ((FloatBuffer) dest).put(src, offset, length); + } else if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + for(int i=0; i<length; ++i) { + b.put(src[offset+i]); + } + return (B)b; + } else { + throw new IllegalArgumentException("Float doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B putd(final B dest, final double v) { + if (dest instanceof DoubleBuffer) { + return (B) ((DoubleBuffer) dest).put(v); + } else if (dest instanceof FloatBuffer) { return (B) ((FloatBuffer) dest).put((float) v); } else { throw new IllegalArgumentException("Double doesn't match Buffer Class: " + dest); } } + @SuppressWarnings("unchecked") + public static <B extends Buffer> B put3d(final B dest, final double v1, final double v2, final double v3) { + if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put((float) v1); + b.put((float) v2); + b.put((float) v3); + return (B)b; + } else { + throw new IllegalArgumentException("Double doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B put4d(final B dest, final double v1, final double v2, final double v3, final double v4) { + if (dest instanceof DoubleBuffer) { + final DoubleBuffer b = (DoubleBuffer) dest; + b.put(v1); + b.put(v2); + b.put(v3); + b.put(v4); + return (B)b; + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + b.put((float) v1); + b.put((float) v2); + b.put((float) v3); + b.put((float) v4); + return (B)b; + } else { + throw new IllegalArgumentException("Double doesn't match Buffer Class: " + dest); + } + } + + @SuppressWarnings("unchecked") + public static <B extends Buffer> B putd(final B dest, final double[] src, final int offset, final int length) { + if (dest instanceof DoubleBuffer) { + return (B) ((DoubleBuffer) dest).put(src, offset, length); + } else if (dest instanceof FloatBuffer) { + final FloatBuffer b = (FloatBuffer) dest; + for(int i=0; i<length; ++i) { + b.put((float) src[offset+i]); + } + return (B)b; + } else { + throw new IllegalArgumentException("Float doesn't match Buffer Class: " + dest); + } + } + //---------------------------------------------------------------------- // Convenient put methods with generic target Buffer and value range conversion, i.e. normalization // @@ -1177,7 +1644,7 @@ public class Buffers { final Method[] _mbbCleaner = { null }; final Method[] _cClean = { null }; final boolean hasCleaner; - if( AccessController.doPrivileged(new PrivilegedAction<Boolean>() { + if( SecurityUtil.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { try { diff --git a/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java b/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java index 6a56d6e..f0bf321 100644 --- a/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java +++ b/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java @@ -38,9 +38,10 @@ import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; -import jogamp.common.Debug; +import com.jogamp.common.os.Platform.OSType; -import com.jogamp.common.os.Platform; +import jogamp.common.Debug; +import jogamp.common.os.PlatformPropsImpl; /** * An {@link InputStream} implementation based on an underlying {@link FileChannel}'s memory mapped {@link ByteBuffer}, @@ -136,8 +137,7 @@ public class MappedByteBufferInputStream extends InputStream { static final boolean DEBUG; static { - Platform.initSingleton(); - if( Platform.is32Bit() ) { + if( PlatformPropsImpl.CPU_ARCH.is32Bit ) { DEFAULT_SLICE_SHIFT = 29; } else { DEFAULT_SLICE_SHIFT = 30; @@ -366,7 +366,7 @@ public class MappedByteBufferInputStream extends InputStream { currentPosition = -1L; } if( fc.size() != newTotalSize ) { - if( Platform.OSType.WINDOWS == Platform.getOSType() ) { + if( OSType.WINDOWS == PlatformPropsImpl.OS_TYPE ) { // On Windows, we have to close all mapped slices. // Otherwise we will receive: // java.io.IOException: The requested operation cannot be performed on a file with a user-mapped section open diff --git a/src/java/com/jogamp/common/os/Clock.java b/src/java/com/jogamp/common/os/Clock.java new file mode 100644 index 0000000..9380442 --- /dev/null +++ b/src/java/com/jogamp/common/os/Clock.java @@ -0,0 +1,165 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020-2023 Gothel Software e.K. + * Copyright (c) 2020-2023 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.jogamp.common.os; + +import java.time.Instant; + +public class Clock { + private static final Instant t0; + static { + Platform.initSingleton(); // loads native gluegen_rt library + { + final long[/*2*/] val = { 0, 0 }; + if( getMonotonicStartupTimeImpl(val) ) { + t0 = Instant.ofEpochSecond(val[0], val[1]); + } else { + t0 = Instant.EPOCH; + } + } + } + + /** + * Returns current monotonic time since Unix Epoch `00:00:00 UTC on 1970-01-01`. + * <p> + * Returned timespec is passing machine precision and range of the underlying native API. + * </p> + * <p> + * Monotonic time shall be used for high-performance measurements of durations, + * since the underlying OS shall support fast calls. + * </p> + * <p> + * Note that {@link #currentNanos()} and {@link #getMonotonicNanos()} + * perform much better than this method, since they only return one long nanosecond value + * since module startup. <br/> + * The implementation of this method needs to write two long values into an array. + * </p> + * @see #getMonotonicStartupTime() + * @see #currentNanos() + * @see #getMonotonicNanos() + * @see #getWallClockTime() + */ + public static Instant getMonotonicTime() { + final long[/*2*/] val = { 0, 0 }; + if( getMonotonicTimeImpl(val) ) { + return Instant.ofEpochSecond(val[0], val[1]); + } else { + return Instant.EPOCH; + } + } + private static native boolean getMonotonicTimeImpl(final long[/*2*/] val); + + /** + * Returns current wall-clock real-time since Unix Epoch `00:00:00 UTC on 1970-01-01`. + * <p> + * Returned Instant is passing machine precision and range of the underlying native API. + * </p> + * <p> + * Wall-Clock time shall be used for accurate measurements of the actual time only, + * since the underlying OS unlikely supports fast calls. + * </p> + * @see #getMonotonicStartupTime() + * @see #currentNanos() + * @see #getMonotonicNanos() + * @see #getMonotonicTime() + */ + public static Instant getWallClockTime() { + final long[/*2*/] val = { 0, 0 }; + if( getWallClockTimeImpl(val) ) { + return Instant.ofEpochSecond(val[0], val[1]); + } else { + return Instant.EPOCH; + } + } + private static native boolean getWallClockTimeImpl(final long[/*2*/] val); + + /** + * Returns the monotonic startup time since module startup as used in {@link #currentNanos()} and {@link #getMonotonicNanos()}. + * @see #currentNanos() + * @see #getMonotonicNanos() + */ + public static Instant getMonotonicStartupTime() { return t0; } + private static native boolean getMonotonicStartupTimeImpl(final long[/*2*/] val); + + /** + * Returns current monotonic nanoseconds since start of this application. + * <p> + * Monotonic time shall be used for high-performance measurements of durations, + * since the underlying OS shall support fast calls. + * </p> + * <p> + * The returned nanoseconds are counted not from Unix Epoch but start of this module, + * hence it lasts for 9'223'372'036 seconds or 292 years using the 64-bit type `long`. + * </p> + * <p> + * Method name doesn't include the term `Time` intentionally, + * since the returned value represent the nanoseconds duration since module start. + * </p> + * @see #getMonotonicStartupTime() + * @see #getMonotonicNanos() + */ + public static native long currentNanos(); + + /** + * Returns the Instant presentation of monotonic {@link #currentNanos()}. + * <p> + * Monotonic time shall be used for high-performance measurements of durations, + * since the underlying OS shall support fast calls. + * </p> + * <p> + * The returned nanoseconds are counted not from Unix Epoch but start of this module, + * hence it lasts for 9'223'372'036 seconds or 292 years using the 64-bit type `long`. + * </p> + * <p> + * Method name doesn't include the term `Time` intentionally, + * since the returned value represent the nanoseconds duration since module start. + * </p> + * @see #getMonotonicStartupTime() + * @see #currentNanos() + */ + public static Instant getMonotonicNanos() { + final long nanos = currentNanos(); + return Instant.ofEpochSecond(nanos/1000000000L, nanos%1000000000L); + } + + /** + * Returns current monotonic time in milliseconds. + * + * @see #getMonotonicStartupTime() + * @see #currentNanos() + * @see #getMonotonicNanos() + */ + public static native long currentTimeMillis(); + + /** + * Returns current wall-clock system `time of day` in seconds since Unix Epoch + * `00:00:00 UTC on 1 January 1970`. + * + * @see #getWallClockTime() + * @see #getMonotonicTime() + * @see #currentNanos() + * @see #getMonotonicNanos() + */ + public static native long wallClockSeconds(); +} diff --git a/src/java/com/jogamp/common/os/NativeLibrary.java b/src/java/com/jogamp/common/os/NativeLibrary.java index 2a42bed..53db784 100644 --- a/src/java/com/jogamp/common/os/NativeLibrary.java +++ b/src/java/com/jogamp/common/os/NativeLibrary.java @@ -41,11 +41,12 @@ package com.jogamp.common.os; import java.io.File; +import java.io.IOException; import java.lang.reflect.Method; import java.net.URISyntaxException; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; @@ -59,6 +60,7 @@ import jogamp.common.os.WindowsDynamicLinkerImpl; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.SecurityUtil; import com.jogamp.common.util.cache.TempJarCache; /** Provides low-level, relatively platform-independent access to @@ -78,6 +80,7 @@ public final class NativeLibrary implements DynamicLookupHelper { private static final String[] prefixes; private static final String[] suffixes; private static final boolean isOSX; + private static String sys_env_lib_path_varname; static { // Instantiate dynamic linker implementation @@ -85,6 +88,7 @@ public final class NativeLibrary implements DynamicLookupHelper { case WINDOWS: prefixes = new String[] { "" }; suffixes = new String[] { ".dll" }; + sys_env_lib_path_varname = "PATH"; isOSX = false; break; @@ -92,6 +96,7 @@ public final class NativeLibrary implements DynamicLookupHelper { case IOS: prefixes = new String[] { "lib" }; suffixes = new String[] { ".dylib" }; + sys_env_lib_path_varname = "DYLD_LIBRARY_PATH"; isOSX = true; break; @@ -105,6 +110,7 @@ public final class NativeLibrary implements DynamicLookupHelper { default: prefixes = new String[] { "lib" }; suffixes = new String[] { ".so" }; + sys_env_lib_path_varname = "LD_LIBRARY_PATH"; isOSX = false; break; } @@ -138,6 +144,35 @@ public final class NativeLibrary implements DynamicLookupHelper { return "NativeLibrary[" + dynLink.getClass().getSimpleName() + ", " + libraryPath + ", 0x" + Long.toHexString(libraryHandle) + ", global " + global + "]"; } + /** + * Returns the system's environment variable name used for the dynamic linker to resolve library locations, e.g. + * - Windows: PATH + * - MacOS: DYLD_LIBRARY_PATH + * - Unix: LD_LIBRARY_PATH + */ + public static final String getSystemEnvLibraryPathVarname() { return sys_env_lib_path_varname; } + + /** + * Returns a list of system paths, from the {@link #getSystemEnvLibraryPathVarname()} variable. + */ + public static final List<String> getSystemEnvLibraryPaths() { + final String paths = + SecurityUtil.doPrivileged(new PrivilegedAction<String>() { + @Override + public String run() { + return System.getenv(getSystemEnvLibraryPathVarname()); + } + }); + final List<String> res = new ArrayList<String>(); + if( null != paths && paths.length() > 0 ) { + final StringTokenizer st = new StringTokenizer(paths, File.pathSeparator); + while (st.hasMoreTokens()) { + res.add(st.nextToken()); + } + } + return res; + } + /** Opens the given native library, assuming it has the same base name on all platforms. <p> @@ -418,29 +453,44 @@ public final class NativeLibrary implements DynamicLookupHelper { final List<String> paths = new ArrayList<String>(); final String libName = selectName(windowsLibName, unixLibName, macOSXLibName); if (libName == null) { - return paths; + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: empty, no libName selected"); + } + return paths; + } + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: libName '"+libName+"'"); } // Allow user's full path specification to override our building of paths final File file = new File(libName); if (file.isAbsolute()) { paths.add(libName); + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: done, absolute path found '"+libName+"'"); + } return paths; } final String[] baseNames = buildNames(libName); + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: baseNames: "+Arrays.toString(baseNames)); + } if( searchSystemPath && searchSystemPathFirst ) { // Add just the library names to use the OS's search algorithm for (int i = 0; i < baseNames.length; i++) { + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: add.ssp_1st: "+baseNames[i]); + } paths.add(baseNames[i]); } // Add probable Mac OS X-specific paths if ( isOSX ) { // Add historical location - addPaths("/Library/Frameworks/" + libName + ".framework", baseNames, paths); + addAbsPaths("add.ssp_1st_macos_old", "/Library/Frameworks/" + libName + ".framework", baseNames, paths); // Add current location - addPaths("/System/Library/Frameworks/" + libName + ".framework", baseNames, paths); + addAbsPaths("add.ssp_1st_macos_cur", "/System/Library/Frameworks/" + libName + ".framework", baseNames, paths); } } @@ -448,12 +498,15 @@ public final class NativeLibrary implements DynamicLookupHelper { // from the LWJGL library final String clPath = findLibrary(libName, loader); if (clPath != null) { - paths.add(clPath); + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: add.clp: "+clPath); + } + paths.add(clPath); } // Add entries from java.library.path final String[] javaLibraryPaths = - AccessController.doPrivileged(new PrivilegedAction<String[]>() { + SecurityUtil.doPrivileged(new PrivilegedAction<String[]>() { @Override public String[] run() { int count = 0; @@ -488,39 +541,44 @@ public final class NativeLibrary implements DynamicLookupHelper { for( int i=0; i < javaLibraryPaths.length; i++ ) { final StringTokenizer tokenizer = new StringTokenizer(javaLibraryPaths[i], File.pathSeparator); while (tokenizer.hasMoreTokens()) { - addPaths(tokenizer.nextToken(), baseNames, paths); + addRelPaths("add.java.library.path", tokenizer.nextToken(), baseNames, paths); } } } // Add current working directory final String userDir = - AccessController.doPrivileged(new PrivilegedAction<String>() { + SecurityUtil.doPrivileged(new PrivilegedAction<String>() { @Override public String run() { return System.getProperty("user.dir"); } }); - addPaths(userDir, baseNames, paths); + addAbsPaths("add.user.dir.std", userDir, baseNames, paths); // Add current working directory + natives/os-arch/ + library names // to handle Bug 1145 cc1 using an unpacked fat-jar - addPaths(userDir+File.separator+"natives"+File.separator+PlatformPropsImpl.os_and_arch+File.separator, baseNames, paths); + addAbsPaths("add.user.dir.fat", userDir+File.separator+"natives"+File.separator+PlatformPropsImpl.os_and_arch, baseNames, paths); if( searchSystemPath && !searchSystemPathFirst ) { // Add just the library names to use the OS's search algorithm for (int i = 0; i < baseNames.length; i++) { + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: add.ssp_lst: "+baseNames[i]); + } paths.add(baseNames[i]); } // Add probable Mac OS X-specific paths if ( isOSX ) { // Add historical location - addPaths("/Library/Frameworks/" + libName + ".Framework", baseNames, paths); + addAbsPaths("add.ssp_lst_macos_old", "/Library/Frameworks/" + libName + ".Framework", baseNames, paths); // Add current location - addPaths("/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths); + addAbsPaths("add.ssp_lst_macos_cur", "/System/Library/Frameworks/" + libName + ".Framework", baseNames, paths); } } - + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: done: "+paths.toString()); + } return paths; } @@ -600,10 +658,27 @@ public final class NativeLibrary implements DynamicLookupHelper { return res; } - private static final void addPaths(final String path, final String[] baseNames, final List<String> paths) { - for (int j = 0; j < baseNames.length; j++) { - paths.add(path + File.separator + baseNames[j]); - } + private static final void addRelPaths(final String cause, final String path, final String[] baseNames, final List<String> paths) { + final String abs_path; + try { + final File fpath = new File(path); + abs_path = fpath.getCanonicalPath(); + } catch( final IOException ioe ) { + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: "+cause+": Exception "+ioe.getMessage()+", from path "+path); + } + return; + } + addAbsPaths(cause, abs_path, baseNames, paths); + } + private static final void addAbsPaths(final String cause, final String abs_path, final String[] baseNames, final List<String> paths) { + for (int j = 0; j < baseNames.length; j++) { + final String p = abs_path + File.separator + baseNames[j]; + if (DEBUG) { + System.err.println("NativeLibrary.enumerateLibraryPaths: "+cause+": "+p+", from path "+abs_path); + } + paths.add(p); + } } private static boolean initializedFindLibraryMethod = false; @@ -616,7 +691,7 @@ public final class NativeLibrary implements DynamicLookupHelper { return null; } if (!initializedFindLibraryMethod) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { @@ -633,7 +708,7 @@ public final class NativeLibrary implements DynamicLookupHelper { } if (findLibraryMethod != null) { try { - return AccessController.doPrivileged(new PrivilegedAction<String>() { + return SecurityUtil.doPrivileged(new PrivilegedAction<String>() { @Override public String run() { try { diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java index ca3d60b..ffea42c 100644 --- a/src/java/com/jogamp/common/os/Platform.java +++ b/src/java/com/jogamp/common/os/Platform.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2010-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -28,7 +28,6 @@ package com.jogamp.common.os; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.TimeUnit; @@ -37,6 +36,7 @@ import com.jogamp.common.net.Uri; import com.jogamp.common.util.JarUtil; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.SecurityUtil; import com.jogamp.common.util.VersionNumber; import com.jogamp.common.util.cache.TempJarCache; @@ -287,7 +287,7 @@ public class Platform extends PlatformPropsImpl { final boolean[] _USE_TEMP_JAR_CACHE = new boolean[] { false }; final boolean[] _AWT_AVAILABLE = new boolean[] { false }; - AccessController.doPrivileged(new PrivilegedAction<Object>() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { @@ -521,26 +521,12 @@ public class Platform extends PlatformPropsImpl { // /** - * Returns the unix based current time in milliseconds, based on <code>gettimeofday(..)</code>. - * <p> - * This is an alternative to {@link System#currentTimeMillis()} and {@link System#nanoTime()}. - * While the named {@link System} methods do provide the required precision, - * <code>gettimeofday()</code> <i>also</i> guarantees time accuracy, i.e. update interval. - * </p> - * @see #currentTimeMicros() - */ - public static native long currentTimeMillis(); - - /** - * Returns the unix based current time in microseconds, based on <code>gettimeofday(..)</code>. - * <p> - * This is an alternative to {@link System#currentTimeMillis()} and {@link System#nanoTime()}. - * While the named {@link System} methods do provide the required precision, - * <code>gettimeofday()</code> <i>also</i> guarantees time accuracy, i.e. update interval. - * </p> - * @see #currentTimeMillis() + * Returns the unix based current time in milliseconds, see {@link Clock#currentTimeMillis()}. + * @see Clock#currentTimeMillis() */ - public static native long currentTimeMicros(); + public static long currentTimeMillis() { + return Clock.currentTimeMillis(); + } /** * Returns the estimated sleep jitter value in nanoseconds. @@ -554,11 +540,11 @@ public class Platform extends PlatformPropsImpl { } private static long getCurrentSleepJitterImpl(final long nsDuration, final int splitInLoops) { final long nsPeriod = nsDuration / splitInLoops; - final long t0_ns = System.nanoTime(); + final long t0_ns = Clock.currentNanos(); for(int i=splitInLoops; i>0; i--) { try { TimeUnit.NANOSECONDS.sleep(nsPeriod); } catch (final InterruptedException e) { } } - return ( ( System.nanoTime() - t0_ns ) - nsDuration ) / splitInLoops; + return ( ( Clock.currentNanos() - t0_ns ) - nsDuration ) / splitInLoops; } } diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java index 380cb00..e68c3b3 100644 --- a/src/java/com/jogamp/common/util/IOUtil.java +++ b/src/java/com/jogamp/common/util/IOUtil.java @@ -48,7 +48,6 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.nio.ByteBuffer; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.List; @@ -79,7 +78,7 @@ public class IOUtil { static { final boolean _props[] = { false, false, false, false, false, false }; - final Method[] res = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { + final Method[] res = SecurityUtil.doPrivileged(new PrivilegedAction<Method[]>() { @Override public Method[] run() { final Method[] res = new Method[] { null, null }; @@ -172,7 +171,7 @@ public class IOUtil { */ /** - * Copy the specified URL resource to the specified output file. The total + * Copy the complete specified URL resource to the specified output file. The total * number of bytes written is returned. * * @param conn the open URLConnection @@ -186,7 +185,7 @@ public class IOUtil { int totalNumBytes = 0; final InputStream in = new BufferedInputStream(conn.getInputStream()); try { - totalNumBytes = copyStream2File(in, outFile, conn.getContentLength()); + totalNumBytes = copyStream2File(in, outFile); } finally { in.close(); } @@ -194,51 +193,47 @@ public class IOUtil { } /** - * Copy the specified input stream to the specified output file. The total + * Copy the complete specified input stream to the specified output file. The total * number of bytes written is returned. * * @param in the source * @param outFile the destination - * @param totalNumBytes informal number of expected bytes, maybe used for user feedback while processing. -1 if unknown * @return * @throws IOException */ - public static int copyStream2File(final InputStream in, final File outFile, int totalNumBytes) throws IOException { + public static int copyStream2File(final InputStream in, final File outFile) throws IOException { final OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile)); try { - totalNumBytes = copyStream2Stream(in, out, totalNumBytes); + return copyStream2Stream(in, out); } finally { out.close(); } - return totalNumBytes; } /** - * Copy the specified input stream to the specified output stream. The total + * Copy the complete specified input stream to the specified output stream. The total * number of bytes written is returned. * * @param in the source * @param out the destination - * @param totalNumBytes informal number of expected bytes, maybe used for user feedback while processing. -1 if unknown * @return * @throws IOException */ - public static int copyStream2Stream(final InputStream in, final OutputStream out, final int totalNumBytes) throws IOException { - return copyStream2Stream(Platform.getMachineDataInfo().pageSizeInBytes(), in, out, totalNumBytes); + public static int copyStream2Stream(final InputStream in, final OutputStream out) throws IOException { + return copyStream2Stream(Platform.getMachineDataInfo().pageSizeInBytes(), in, out); } /** - * Copy the specified input stream to the specified output stream. The total + * Copy the complete specified input stream to the specified output stream. The total * number of bytes written is returned. * * @param bufferSize the intermediate buffer size, should be {@link MachineDataInfo#pageSizeInBytes()} for best performance. * @param in the source * @param out the destination - * @param totalNumBytes informal number of expected bytes, maybe used for user feedback while processing. -1 if unknown * @return * @throws IOException */ - public static int copyStream2Stream(final int bufferSize, final InputStream in, final OutputStream out, final int totalNumBytes) throws IOException { + public static int copyStream2Stream(final int bufferSize, final InputStream in, final OutputStream out) throws IOException { final byte[] buf = new byte[bufferSize]; int numBytes = 0; while (true) { @@ -262,7 +257,7 @@ public class IOUtil { } /** - * Copy the specified input stream to a byte array, which is being returned. + * Copy the complete specified input stream to a byte array, which is being returned. */ public static byte[] copyStream2ByteArray(InputStream stream) throws IOException { if( !(stream instanceof BufferedInputStream) ) { @@ -295,8 +290,7 @@ public class IOUtil { } /** - * Copy the specified input stream to a NIO ByteBuffer w/ native byte order, which is being returned. - * <p>The implementation creates the ByteBuffer w/ {@link #copyStream2ByteArray(InputStream)}'s returned byte array.</p> + * Copy the complete specified input stream to a NIO ByteBuffer w/ native byte order, which is being returned. * * @param stream input stream, which will be wrapped into a BufferedInputStream, if not already done. */ @@ -305,11 +299,10 @@ public class IOUtil { } /** - * Copy the specified input stream to a NIO ByteBuffer w/ native byte order, which is being returned. - * <p>The implementation creates the ByteBuffer w/ {@link #copyStream2ByteArray(InputStream)}'s returned byte array.</p> + * Copy the complete specified input stream to a NIO ByteBuffer w/ native byte order, which is being returned. * * @param stream input stream, which will be wrapped into a BufferedInputStream, if not already done. - * @param initialCapacity initial buffer capacity in bytes, if > available bytes + * @param initialCapacity initial buffer capacity in bytes, if < currently available bytes, initial buffer capacity is set to currently available bytes. */ public static ByteBuffer copyStream2ByteBuffer(InputStream stream, int initialCapacity) throws IOException { if( !(stream instanceof BufferedInputStream) ) { @@ -344,6 +337,39 @@ public class IOUtil { return data; } + /** + * Copy the specified input stream chunk to a NIO ByteBuffer w/ native byte order, which is being returned. + * + * @param stream input stream, which will be wrapped into a BufferedInputStream, if not already done. + * @param skipBytes initial bytes to skip from input stream. + * @param byteCount bytes to copy starting after skipBytes. + */ + public static ByteBuffer copyStreamChunk2ByteBuffer(InputStream stream, int skipBytes, int byteCount) throws IOException { + if( !(stream instanceof BufferedInputStream) ) { + stream = new BufferedInputStream(stream); + } + final MachineDataInfo machine = Platform.getMachineDataInfo(); + final ByteBuffer data = Buffers.newDirectByteBuffer( machine.pageAlignedSize( byteCount ) ); + final byte[] chunk = new byte[machine.pageSizeInBytes()]; + int numRead = 1; // EOS: -1 == numRead, EOF maybe reached earlier w/ 0 == numRead + while ( numRead > 0 && skipBytes > 0 ) { + final int chunk2Read = Math.min(machine.pageSizeInBytes(), skipBytes); + numRead = stream.read(chunk, 0, chunk2Read); + skipBytes -= numRead; + } + while ( numRead > 0 && byteCount > 0 ) { + final int chunk2Read = Math.min(machine.pageSizeInBytes(), byteCount); + numRead = stream.read(chunk, 0, chunk2Read); + if (numRead > 0) { + data.put(chunk, 0, numRead); + } + byteCount -= numRead; + } + + data.flip(); + return data; + } + /*** * * RESOURCE / FILE NAME STUFF diff --git a/src/java/com/jogamp/common/util/IntIntHashMap.java b/src/java/com/jogamp/common/util/IntIntHashMap.java index f78b1e0..d74b79c 100644 --- a/src/java/com/jogamp/common/util/IntIntHashMap.java +++ b/src/java/com/jogamp/common/util/IntIntHashMap.java @@ -34,7 +34,6 @@ package com.jogamp.common.util; import com.jogamp.common.JogampRuntimeException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; @@ -84,7 +83,7 @@ public class /*name*/IntIntHashMap/*name*/ implements Cloneable, isPrimitive = valueClazz.isPrimitive(); if(!isPrimitive) { - final EntryCM cm = AccessController.doPrivileged(new PrivilegedAction<EntryCM>() { + final EntryCM cm = SecurityUtil.doPrivileged(new PrivilegedAction<EntryCM>() { @Override @SuppressWarnings("unchecked") public EntryCM run() { @@ -502,7 +501,7 @@ public class /*name*/IntIntHashMap/*name*/ implements Cloneable, private static Method getCloneMethod(final Object obj) { final Class<?> clazz = obj.getClass(); - return AccessController.doPrivileged(new PrivilegedAction<Method>() { + return SecurityUtil.doPrivileged(new PrivilegedAction<Method>() { @Override public Method run() { try { diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java index aa5719c..9dc0fb6 100644 --- a/src/java/com/jogamp/common/util/JarUtil.java +++ b/src/java/com/jogamp/common/util/JarUtil.java @@ -418,14 +418,25 @@ public class JarUtil { * <pre> * class's jar url path + cutOffInclSubDir + relResPath, * </pre> + * or with <code>cutOffInclSubDir</code> being <code>null</code> just + * <pre> + * class's jar url path + relResPath, + * </pre> * Example #1 * <pre> * classFromJavaJar = com.lighting.Test (in: file:/storage/TestLighting.jar) + * cutOffInclSubDir = null + * relResPath = LightAssets.jar + * Result : file:/storage/LightAssets.jar + * </pre> + * Example #2 + * <pre> + * classFromJavaJar = com.lighting.Test (in: file:/storage/TestLighting.jar) * cutOffInclSubDir = lights/ * relResPath = LightAssets.jar * Result : file:/storage/lights/LightAssets.jar * </pre> - * Example #2 + * Example #3 * <pre> * classFromJavaJar = com.lighting.Test (in: file:/storage/lights/TestLighting.jar) * cutOffInclSubDir = lights/ @@ -436,8 +447,9 @@ public class JarUtil { * TODO: Enhance documentation! * * @param classFromJavaJar Used to get the root Uri for the class's Jar Uri. - * @param cutOffInclSubDir The <i>cut off</i> included sub-directory prepending the relative resource path. + * @param cutOffInclSubDir Optional <i>cut off</i> included sub-directory prepending the relative resource path. * If the root Uri includes cutOffInclSubDir, it is no more added to the result. + * Parameter will be ignored if <code>null</code>. * @param relResPath The relative resource path. (Uri encoded) * @return The resulting resource Uri, which is not tested. * @throws IllegalArgumentException @@ -451,7 +463,6 @@ public class JarUtil { System.err.println("JarUtil.getRelativeOf: "+"(classFromJavaJar "+classFromJavaJar+", classJarUri "+classJarUri+ ", cutOffInclSubDir "+cutOffInclSubDir+", relResPath "+relResPath+"): "); } - final Uri jarSubUri = classJarUri.getContainedUri(); if(null == jarSubUri) { throw new IllegalArgumentException("JarSubUri is null of: "+classJarUri); @@ -460,9 +471,8 @@ public class JarUtil { if( DEBUG ) { System.err.println("JarUtil.getRelativeOf: "+"uri "+jarSubUri.toString()+" -> "+jarUriRoot); } - final Uri.Encoded resUri; - if( jarUriRoot.endsWith(cutOffInclSubDir.get()) ) { + if( null == cutOffInclSubDir || jarUriRoot.endsWith(cutOffInclSubDir.get()) ) { resUri = jarUriRoot.concat(relResPath); } else { resUri = jarUriRoot.concat(cutOffInclSubDir).concat(relResPath); @@ -470,7 +480,6 @@ public class JarUtil { if( DEBUG ) { System.err.println("JarUtil.getRelativeOf: "+"... -> "+resUri); } - final Uri resJarUri = JarUtil.getJarFileUri(resUri); if( DEBUG ) { System.err.println("JarUtil.getRelativeOf: "+"fin "+resJarUri); @@ -628,7 +637,7 @@ public class JarUtil { final OutputStream out = new BufferedOutputStream(new FileOutputStream(destFile)); int numBytes = -1; try { - numBytes = IOUtil.copyStream2Stream(BUFFER_SIZE, in, out, -1); + numBytes = IOUtil.copyStream2Stream(BUFFER_SIZE, in, out); } finally { in.close(); out.close(); diff --git a/src/java/com/jogamp/common/util/PerfCounterCtrl.java b/src/java/com/jogamp/common/util/PerfCounterCtrl.java new file mode 100644 index 0000000..2c79a2d --- /dev/null +++ b/src/java/com/jogamp/common/util/PerfCounterCtrl.java @@ -0,0 +1,50 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2023 Gothel Software e.K. + * Copyright (c) 2023 JogAmp Community. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.jogamp.common.util; + +import java.io.PrintStream; +import com.jogamp.common.os.Clock; + +/** + * Simple performance counter controller. + * <p> + * Implementation is expected to utilize nanosecond counter since module start, + * e.g. {@link Clock#currentNanos()}. + * </p> + */ +public interface PerfCounterCtrl { + /** Enable or disable performance counter. */ + void enable(final boolean enable); + + /** Clear performance counter. */ + void clear(); + + /** Return the total duration in nanoseconds, covering all sub-counter. */ + long getTotalDuration(); + + /** Print performance counter. */ + void print(final PrintStream out); +} diff --git a/src/java/com/jogamp/common/util/PropertyAccess.java b/src/java/com/jogamp/common/util/PropertyAccess.java index b6e9bdd..6dd550b 100644 --- a/src/java/com/jogamp/common/util/PropertyAccess.java +++ b/src/java/com/jogamp/common/util/PropertyAccess.java @@ -175,7 +175,7 @@ public class PropertyAccess { } private static final String getTrustedPropKey(final String propertyKey) { - return AccessController.doPrivileged(new PrivilegedAction<String>() { + return SecurityUtil.doPrivileged(new PrivilegedAction<String>() { @Override public String run() { try { diff --git a/src/java/com/jogamp/common/util/ReflectionUtil.java b/src/java/com/jogamp/common/util/ReflectionUtil.java index 0d76827..27ca983 100644 --- a/src/java/com/jogamp/common/util/ReflectionUtil.java +++ b/src/java/com/jogamp/common/util/ReflectionUtil.java @@ -51,6 +51,7 @@ import jogamp.common.Debug; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.JogampRuntimeException; +import com.jogamp.common.os.Clock; public final class ReflectionUtil { @@ -125,9 +126,9 @@ public final class ReflectionUtil { private static Class<?> getClassImpl(final String clazzName, final boolean initializeClazz, final ClassLoader cl) throws ClassNotFoundException { if(DEBUG_STATS_FORNAME) { - final long t0 = System.nanoTime(); + final long t0 = Clock.currentNanos(); final Class<?> res = Class.forName(clazzName, initializeClazz, cl); - final long t1 = System.nanoTime(); + final long t1 = Clock.currentNanos(); final long nanoCosts = t1 - t0; synchronized(forNameLock) { forNameCount++; diff --git a/src/java/com/jogamp/common/util/SecurityUtil.java b/src/java/com/jogamp/common/util/SecurityUtil.java index 1b8b7c2..6d5b639 100644 --- a/src/java/com/jogamp/common/util/SecurityUtil.java +++ b/src/java/com/jogamp/common/util/SecurityUtil.java @@ -27,7 +27,6 @@ */ package com.jogamp.common.util; -import java.security.AccessController; import java.security.AllPermission; import java.security.CodeSource; import java.security.Permission; @@ -35,19 +34,63 @@ import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; +import jogamp.common.os.PlatformPropsImpl; + public class SecurityUtil { + @SuppressWarnings("removal") private static final SecurityManager securityManager; private static final Permission allPermissions; private static final boolean DEBUG = false; + /** + * Call wrapper for {@link System#getSecurityManager()}. + * <p> + * {@link System#getSecurityManager()} is deprecated + * since Java 17 (JEP 411) and earmarked to be removed.<br/> + * </p> + * <p> + * On a Java 17 machine, this method will simply return null. + * </p> + */ + @SuppressWarnings({ "deprecation", "removal" }) + public static final SecurityManager getSecurityManager() { + if( PlatformPropsImpl.JAVA_17 ) { + return null; + } else { + return System.getSecurityManager(); + } + } + + /** + * Call wrapper for {@link java.security.AccessController#doPrivileged(PrivilegedAction)}. + * <p> + * {@link java.security.AccessController#doPrivileged(PrivilegedAction)} is deprecated + * since Java 17 (JEP 411) and earmarked to be removed.<br/> + * </p> + * <p> + * On a Java 17 machine, this method will simply invoke the given PrivilegedAction<T>. + * </p> + * @param <T> return type of PrivilegedAction<T> + * @param o the PrivilegedAction<T> + * @return the return type + */ + @SuppressWarnings({ "deprecation", "removal" }) + public static <T> T doPrivileged(final PrivilegedAction<T> o) { + if( PlatformPropsImpl.JAVA_17 ) { + return o.run(); + } else { + return java.security.AccessController.doPrivileged( o ); + } + } + static { allPermissions = new AllPermission(); - securityManager = System.getSecurityManager(); + securityManager = getSecurityManager(); if( DEBUG ) { final boolean hasAllPermissions; { - final ProtectionDomain insecPD = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() { + final ProtectionDomain insecPD = doPrivileged(new PrivilegedAction<ProtectionDomain>() { @Override public ProtectionDomain run() { return SecurityUtil.class.getProtectionDomain(); @@ -64,7 +107,7 @@ public class SecurityUtil { System.err.println("SecurityUtil: Has SecurityManager: "+ ( null != securityManager ) ) ; System.err.println("SecurityUtil: Has AllPermissions: "+hasAllPermissions); - final Certificate[] certs = AccessController.doPrivileged(new PrivilegedAction<Certificate[]>() { + final Certificate[] certs = doPrivileged(new PrivilegedAction<Certificate[]>() { @Override public Certificate[] run() { return getCerts(SecurityUtil.class); diff --git a/src/java/com/jogamp/common/util/UnsafeUtil.java b/src/java/com/jogamp/common/util/UnsafeUtil.java index 6fde3fa..d1b2dd8 100644 --- a/src/java/com/jogamp/common/util/UnsafeUtil.java +++ b/src/java/com/jogamp/common/util/UnsafeUtil.java @@ -31,7 +31,6 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.ByteBuffer; -import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.ExceptionUtils; @@ -73,7 +72,7 @@ public class UnsafeUtil { final Class<?>[] _illegalAccessLoggerClass = { null }; final Long[] _loggerOffset = { null }; - AccessController.doPrivileged(new PrivilegedAction<Object>() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { Class<?> unsafeClass = null; @@ -172,7 +171,7 @@ public class UnsafeUtil { /** * Issue the given user {@code action} while {@code jdk.internal.module.IllegalAcessLogger}'s {@code logger} has been temporarily disabled. * <p> - * The caller shall place this call into their own {@link AccessController#doPrivileged(PrivilegedAction)} block. + * The caller shall place this call into their own {@link SecurityUtil#doPrivileged(PrivilegedAction)} block. * </p> * <p> * In case the runtime is not {@link PlatformPropsImpl#JAVA_9} or the logger is not accessible or disabling caused an exception, diff --git a/src/java/com/jogamp/common/util/VersionUtil.java b/src/java/com/jogamp/common/util/VersionUtil.java index 1e09034..eee3c4e 100644 --- a/src/java/com/jogamp/common/util/VersionUtil.java +++ b/src/java/com/jogamp/common/util/VersionUtil.java @@ -73,9 +73,17 @@ public class VersionUtil { sb.append("Platform: Java Version: ").append(Platform.getJavaVersion()).append(" (").append(Platform.getJavaVersionNumber()).append("u").append(PlatformPropsImpl.JAVA_VERSION_UPDATE).append("), VM: ").append(Platform.getJavaVMName()); sb.append(", Runtime: ").append(Platform.getJavaRuntimeName()).append(Platform.getNewline()); sb.append("Platform: Java Vendor: ").append(Platform.getJavaVendor()).append(", ").append(Platform.getJavaVendorURL()); - sb.append(", JavaSE: ").append(PlatformPropsImpl.JAVA_SE); - sb.append(", Java9: ").append(PlatformPropsImpl.JAVA_9); - sb.append(", Java6: ").append(PlatformPropsImpl.JAVA_6); + if( PlatformPropsImpl.JAVA_21 ) { + sb.append(", Java21"); + } else if( PlatformPropsImpl.JAVA_17 ) { + sb.append(", Java17"); + } else if( PlatformPropsImpl.JAVA_9 ) { + sb.append(", Java9"); + } else if( PlatformPropsImpl.JAVA_6 ) { + sb.append(", Java6"); + } else if( PlatformPropsImpl.JAVA_SE ) { + sb.append(", JavaSE"); + } sb.append(", dynamicLib: ").append(PlatformPropsImpl.useDynamicLibraries); sb.append(", AWT enabled: ").append(Platform.AWT_AVAILABLE); sb.append(Platform.getNewline()).append(SEPERATOR); diff --git a/src/java/com/jogamp/common/util/awt/AWTEDTExecutor.java b/src/java/com/jogamp/common/util/awt/AWTEDTExecutor.java index ec9348d..cc5d5d1 100644 --- a/src/java/com/jogamp/common/util/awt/AWTEDTExecutor.java +++ b/src/java/com/jogamp/common/util/awt/AWTEDTExecutor.java @@ -48,17 +48,17 @@ public class AWTEDTExecutor implements RunnableExecutor { if(EventQueue.isDispatchThread()) { r.run(); } else { - try { - if(wait) { - EventQueue.invokeAndWait(r); - } else { - EventQueue.invokeLater(r); + try { + if(wait) { + EventQueue.invokeAndWait(r); + } else { + EventQueue.invokeLater(r); + } + } catch (final InvocationTargetException e) { + throw new RuntimeException(e.getTargetException()); + } catch (final InterruptedException e) { + throw new RuntimeException(e); } - } catch (final InvocationTargetException e) { - throw new RuntimeException(e.getTargetException()); - } catch (final InterruptedException e) { - throw new RuntimeException(e); - } } } diff --git a/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java b/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java index 03ed5c1..2ced962 100644 --- a/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java +++ b/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java @@ -46,7 +46,6 @@ import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Iterator; import java.util.LinkedHashSet; @@ -89,7 +88,7 @@ public abstract class ProcAddressTable { private final FunctionAddressResolver resolver; static { - AccessController.doPrivileged(new PrivilegedAction<Object>() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { DEBUG = (System.getProperty("jogamp.debug.ProcAddressHelper") != null); @@ -207,7 +206,7 @@ public abstract class ProcAddressTable { * </p> */ private final Field fieldForFunctionInSec(final String name) throws IllegalArgumentException { - return AccessController.doPrivileged(new PrivilegedAction<Field>() { + return SecurityUtil.doPrivileged(new PrivilegedAction<Field>() { @Override public Field run() { try { diff --git a/src/java/jogamp/common/Debug.java b/src/java/jogamp/common/Debug.java index 838b607..131018c 100644 --- a/src/java/jogamp/common/Debug.java +++ b/src/java/jogamp/common/Debug.java @@ -28,10 +28,10 @@ package jogamp.common; -import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.util.PropertyAccess; +import com.jogamp.common.util.SecurityUtil; /** Helper routines for logging and debugging. */ @@ -41,7 +41,7 @@ public class Debug extends PropertyAccess { private static final boolean debugAll; static { - AccessController.doPrivileged(new PrivilegedAction<Object>() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { PropertyAccess.addTrustedPrefix("jogamp."); diff --git a/src/java/jogamp/common/av/JavaSoundAudioSink.java b/src/java/jogamp/common/av/JavaSoundAudioSink.java new file mode 100644 index 0000000..58f0fec --- /dev/null +++ b/src/java/jogamp/common/av/JavaSoundAudioSink.java @@ -0,0 +1,320 @@ +/** + * Copyright 2013-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.common.av; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.SourceDataLine; + +import com.jogamp.common.av.AudioFormat; +import com.jogamp.common.av.AudioSink; + +/*** + * JavaSound Audio Sink + * <p> + * FIXME: Parameterize .. all configs .. best via an init-method, passing requested + * audio capabilities + * </p> + */ +public final class JavaSoundAudioSink implements AudioSink { + + // Chunk of audio processed at one time + public static final int BUFFER_SIZE = 1000; + public static final int SAMPLES_PER_BUFFER = BUFFER_SIZE / 2; + private static final boolean staticAvailable; + + // Sample time values + // public static final double SAMPLE_TIME_IN_SECS = 1.0 / DEFAULT_SAMPLE_RATE; + // public static final double BUFFER_TIME_IN_SECS = SAMPLE_TIME_IN_SECS * SAMPLES_PER_BUFFER; + + private javax.sound.sampled.AudioFormat format; + private DataLine.Info info; + private SourceDataLine auline; + private int bufferCount; + private final byte [] sampleData = new byte[BUFFER_SIZE]; + private boolean available = false; + private final AudioFormat nativeFormat; + private int userMaxChannels = 8; + private AudioFormat preferredFormat = null; + private AudioFormat chosenFormat = null; + + private volatile boolean playRequested = false; + private float volume = 1.0f; + + static { + boolean ok = false; + try { + ok = AudioSystem.getAudioFileTypes().length > 0; + } catch (final Throwable t) { + + } + staticAvailable=ok; + } + + public JavaSoundAudioSink() { + available = false; + if( !staticAvailable ) { + nativeFormat = DefaultFormat; + return; + } + nativeFormat = new AudioFormat(DefaultFormat.sampleRate, DefaultFormat.sampleSize, getMaxSupportedChannels(), + DefaultFormat.signed, DefaultFormat.fixedP, DefaultFormat.planar, DefaultFormat.littleEndian); + preferredFormat = nativeFormat; + available = true; + } + + @Override + public final boolean makeCurrent(final boolean throwException) { return true; } + + @Override + public final boolean release(final boolean throwException) { return true; } + + @Override + public String toString() { + return "JavaSoundSink[avail "+available+", dataLine "+info+", source "+auline+", bufferCount "+bufferCount+ + ", chosen "+chosenFormat+", jsFormat "+format; + } + + @Override + public final float getPlaySpeed() { return 1.0f; } // FIXME + + @Override + public final boolean setPlaySpeed(final float rate) { + return false; // FIXME + } + + @Override + public final float getVolume() { + // FIXME + return volume; + } + + @Override + public final boolean setVolume(final float v) { + // FIXME + volume = v; + return true; + } + + @Override + public int getSourceCount() { + return -1; + } + + @Override + public float getDefaultLatency() { + return 20f/1000f; // fake 20ms + } + + @Override + public float getLatency() { + return 20f/1000f; // fake 20ms + } + + @Override + public final AudioFormat getNativeFormat() { + return nativeFormat; + } + + @Override + public AudioFormat getPreferredFormat() { + return DefaultFormat; + } + + @Override + public final void setChannelLimit(final int cc) { + userMaxChannels = Math.min(8, Math.max(1, cc)); + preferredFormat = new AudioFormat(nativeFormat.sampleRate, + nativeFormat.sampleSize, getMaxSupportedChannels(), + nativeFormat.signed, nativeFormat.fixedP, + nativeFormat.planar, nativeFormat.littleEndian); + if( DEBUG ) { + System.out.println("ALAudioSink: channelLimit "+userMaxChannels+", preferredFormat "+preferredFormat); + } + } + + private final int getMaxSupportedChannels() { + final int cc = 2; + return Math.min(userMaxChannels, cc); + } + + @Override + public final boolean isSupported(final AudioFormat format) { + if( format.planar != preferredFormat.planar || + format.fixedP != preferredFormat.fixedP || + format.sampleRate > preferredFormat.sampleRate || + format.channelCount > preferredFormat.channelCount ) + { + return false; + } + return true; + } + + @Override + public boolean init(final AudioFormat requestedFormat, final int frameDuration, final int initialQueueSize, final int queueGrowAmount, final int queueLimit) { + if( !staticAvailable ) { + return false; + } + if( !isSupported(requestedFormat) ) { + return false; + } + // Create the audio format we wish to use + format = new javax.sound.sampled.AudioFormat(requestedFormat.sampleRate, requestedFormat.sampleSize, requestedFormat.channelCount, requestedFormat.signed, !requestedFormat.littleEndian); + + // Create dataline info object describing line format + info = new DataLine.Info(SourceDataLine.class, format); + + // Clear buffer initially + Arrays.fill(sampleData, (byte) 0); + try{ + // Get line to write data to + auline = (SourceDataLine) AudioSystem.getLine(info); + auline.open(format); + auline.start(); + System.out.println("JavaSound audio sink"); + available=true; + chosenFormat = requestedFormat; + } catch (final Exception e) { + available=false; + } + return true; + } + + @Override + public final AudioFormat getChosenFormat() { + return chosenFormat; + } + + @Override + public boolean isPlaying() { + return playRequested && auline.isRunning(); + } + + @Override + public void play() { + if( null != auline ) { + playRequested = true; + playImpl(); + } + } + private void playImpl() { + if( playRequested && !auline.isRunning() ) { + auline.start(); + } + } + + @Override + public void pause() { + if( null != auline ) { + playRequested = false; + auline.stop(); + } + } + + @Override + public void flush() { + if( null != auline ) { + playRequested = false; + auline.stop(); + auline.flush(); + } + } + + @Override + public final int getEnqueuedFrameCount() { + return 0; // FIXME + } + + @Override + public int getFrameCount() { + return 1; + } + + @Override + public int getQueuedFrameCount() { + return 0; + } + + @Override + public boolean isAvailable() { + return available; + } + + @Override + public void destroy() { + available = false; + chosenFormat = null; + // FIXEM: complete code! + } + + @Override + public AudioFrame enqueueData(final int pts, final ByteBuffer byteBuffer, final int byteCount) { + final byte[] bytes = new byte[byteCount]; + final int p = byteBuffer.position(); + byteBuffer.get(bytes, 0, byteCount); + byteBuffer.position(p); + + int written = 0; + int len; + int bytesLeft = byteCount; + while (bytesLeft > 0) { + len = auline.write(bytes, written, byteCount); + bytesLeft -= len; + written += len; + } + playImpl(); + return new AudioDataFrame(pts, Math.round(1000f*chosenFormat.getBytesDuration(byteCount)), byteBuffer, byteCount); + } + + @Override + public int getQueuedByteCount() { + return auline.getBufferSize() - auline.available(); + } + + @Override + public int getFreeFrameCount() { + return auline.available(); + } + + @Override + public float getQueuedTime() { + return chosenFormat.getBytesDuration( getQueuedByteCount() ); + } + + @Override + public float getAvgFrameDuration() { + return 0f; + } + + @Override + public final int getPTS() { return 0; } // FIXME + +} diff --git a/src/java/jogamp/common/av/NullAudioSink.java b/src/java/jogamp/common/av/NullAudioSink.java new file mode 100644 index 0000000..904b863 --- /dev/null +++ b/src/java/jogamp/common/av/NullAudioSink.java @@ -0,0 +1,211 @@ +/** + * Copyright 2013-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.common.av; + +import java.nio.ByteBuffer; + +import com.jogamp.common.av.AudioFormat; +import com.jogamp.common.av.AudioSink; + +public final class NullAudioSink implements AudioSink { + + private volatile float playSpeed = 1.0f; + private volatile boolean playRequested = false; + private volatile int playingPTS = AudioFrame.INVALID_PTS; + private float volume = 1.0f; + + private AudioFormat chosenFormat; + private boolean available; + + public NullAudioSink() { + available = true; + chosenFormat = null; + } + + @Override + public final boolean makeCurrent(final boolean throwException) { return true; } + + @Override + public final boolean release(final boolean throwException) { return true; } + + @Override + public boolean isAvailable() { + return available; + } + + @Override + public final float getPlaySpeed() { return playSpeed; } + + @Override + public final boolean setPlaySpeed(float rate) { + if( Math.abs(1.0f - rate) < 0.01f ) { + rate = 1.0f; + } + playSpeed = rate; + return true; + } + + @Override + public final float getVolume() { + // FIXME + return volume; + } + + @Override + public final boolean setVolume(final float v) { + // FIXME + volume = v; + return true; + } + + @Override + public int getSourceCount() { + return -1; + } + + @Override + public float getDefaultLatency() { + return 0; + } + + @Override + public float getLatency() { + return 0; + } + + @Override + public AudioFormat getNativeFormat() { + return DefaultFormat; + } + + @Override + public AudioFormat getPreferredFormat() { + return DefaultFormat; + } + + @Override + public void setChannelLimit(final int cc) { } + + @Override + public final boolean isSupported(final AudioFormat format) { + /** + * If we like to emulate constraints .. + * + if( format.planar || !format.littleEndian ) { + return false; + } + if( format.sampleRate != DefaultFormat.sampleRate ) { + return false; + } + */ + return true; + } + + @Override + public boolean init(final AudioFormat requestedFormat, final int frameDuration, final int initialQueueSize, final int queueGrowAmount, final int queueLimit) { + chosenFormat = requestedFormat; + return true; + } + + @Override + public final AudioFormat getChosenFormat() { + return chosenFormat; + } + + @Override + public boolean isPlaying() { + return playRequested; + } + + @Override + public void play() { + playRequested = true; + } + + @Override + public void pause() { + playRequested = false; + } + + @Override + public void flush() { + } + + @Override + public void destroy() { + available = false; + chosenFormat = null; + } + + @Override + public final int getEnqueuedFrameCount() { + return 0; + } + + @Override + public int getFrameCount() { + return 0; + } + + @Override + public int getQueuedFrameCount() { + return 0; + } + + @Override + public int getQueuedByteCount() { + return 0; + } + + @Override + public float getQueuedTime() { + return 0f; + } + + @Override + public float getAvgFrameDuration() { + return 0f; + } + + @Override + public final int getPTS() { return playingPTS; } + + @Override + public int getFreeFrameCount() { + return 1; + } + + @Override + public AudioFrame enqueueData(final int pts, final ByteBuffer bytes, final int byteCount) { + if( !available || null == chosenFormat ) { + return null; + } + playingPTS = pts; + return null; + } +} diff --git a/src/java/jogamp/common/os/PlatformPropsImpl.java b/src/java/jogamp/common/os/PlatformPropsImpl.java index 1d38f30..aedf288 100644 --- a/src/java/jogamp/common/os/PlatformPropsImpl.java +++ b/src/java/jogamp/common/os/PlatformPropsImpl.java @@ -6,7 +6,6 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; -import java.security.AccessController; import java.security.PrivilegedAction; import java.util.List; @@ -23,6 +22,7 @@ import com.jogamp.common.os.Platform.ABIType; import com.jogamp.common.os.Platform.CPUFamily; import com.jogamp.common.os.Platform.CPUType; import com.jogamp.common.os.Platform.OSType; +import com.jogamp.common.util.SecurityUtil; import com.jogamp.common.util.VersionNumber; /** @@ -38,16 +38,6 @@ import com.jogamp.common.util.VersionNumber; public abstract class PlatformPropsImpl { static final boolean DEBUG = Debug.debug("Platform"); - /** Selected {@link Platform.OSType#MACOS} or {@link Platform.OSType#IOS} {@link VersionNumber}s. */ - public static class OSXVersion { - /** OSX Tiger, i.e. 10.4.0 */ - public static final VersionNumber Tiger = new VersionNumber(10,4,0); - /** OSX Lion, i.e. 10.7.0 */ - public static final VersionNumber Lion = new VersionNumber(10,7,0); - /** OSX Mavericks, i.e. 10.9.0 */ - public static final VersionNumber Mavericks = new VersionNumber(10,9,0); - } - /** * Returns {@code true} if the given {@link CPUType}s and {@link ABIType}s are compatible. */ @@ -59,15 +49,6 @@ public abstract class PlatformPropsImpl { // static initialization order: // - /** Version 1.6. As a JVM version, it enables certain JVM 1.6 features. */ - public static final VersionNumber Version16; - /** Version 1.7. As a JVM version, it enables certain JVM 1.7 features. */ - public static final VersionNumber Version17; - /** Version 1.8. As a JVM version, it enables certain JVM 1.8 features. */ - public static final VersionNumber Version18; - /** Version 1.9. As a JVM version, it enables certain JVM 1.9 features. Note the skipped first version number due to JEP 223. */ - public static final VersionNumber Version9; - public static final String OS; public static final String OS_lower; public static final String OS_VERSION; @@ -93,10 +74,11 @@ public abstract class PlatformPropsImpl { * </p> */ public static final boolean JAVA_6; + /** * True only if being compatible w/ language level 9, e.g. JRE 9. * <p> - * Implies {@link #isJavaSE()} and {@link #JAVA_6}. + * Implies {@link #JAVA_6} and {@link #isJavaSE()} * </p> * <p> * Since JRE 9, the version string has dropped the major release number, @@ -105,6 +87,22 @@ public abstract class PlatformPropsImpl { */ public static final boolean JAVA_9; + /** + * True only if being compatible w/ language level 17, e.g. JRE 17 (LTS). + * <p> + * Implies {@link #JAVA_9}, {@link #JAVA_6} and {@link #isJavaSE()} + * </p> + */ + public static final boolean JAVA_17; + + /** + * True only if being compatible w/ language level 21, e.g. JRE 21 (LTS). + * <p> + * Implies {@link #JAVA_17}, {@link #JAVA_9}, {@link #JAVA_6} and {@link #isJavaSE()} + * </p> + */ + public static final boolean JAVA_21; + public static final String NEWLINE; public static final boolean LITTLE_ENDIAN; @@ -122,11 +120,6 @@ public abstract class PlatformPropsImpl { public static final boolean useDynamicLibraries; static { - Version16 = new VersionNumber(1, 6, 0); - Version17 = new VersionNumber(1, 7, 0); - Version18 = new VersionNumber(1, 8, 0); - Version9 = new VersionNumber(9, 0, 0); - // We don't seem to need an AccessController.doPrivileged() block // here as these system properties are visible even to unsigned Applets. final boolean isAndroid = AndroidVersion.isAvailable; // also triggers it's static initialization @@ -154,9 +147,41 @@ public abstract class PlatformPropsImpl { JAVA_VM_NAME = System.getProperty("java.vm.name"); JAVA_RUNTIME_NAME = getJavaRuntimeNameImpl(); JAVA_SE = initIsJavaSE(); - JAVA_9 = JAVA_SE && JAVA_VERSION_NUMBER.compareTo(Version9) >= 0; - JAVA_6 = JAVA_SE && ( isAndroid || JAVA_9 || JAVA_VERSION_NUMBER.compareTo(Version16) >= 0 ) ; - + if( JAVA_SE ) { + if( JAVA_VERSION_NUMBER.compareTo(new VersionNumber(21, 0, 0)) >= 0 ) { + JAVA_21 = true; + JAVA_17 = true; + JAVA_9 = true; + JAVA_6 = true; + } else if( JAVA_VERSION_NUMBER.compareTo(new VersionNumber(17, 0, 0)) >= 0 ) { + JAVA_21 = false; + JAVA_17 = true; + JAVA_9 = true; + JAVA_6 = true; + } else if( JAVA_VERSION_NUMBER.compareTo(new VersionNumber(9, 0, 0)) >= 0 ) { + JAVA_21 = false; + JAVA_17 = false; + JAVA_9 = true; + JAVA_6 = true; + } else if( isAndroid || JAVA_VERSION_NUMBER.compareTo(new VersionNumber(1, 6, 0)) >= 0 ) { + JAVA_21 = false; + JAVA_17 = false; + JAVA_9 = false; + JAVA_6 = true; + } else { + // we probably don't support anything below 1.6 + JAVA_21 = false; + JAVA_17 = false; + JAVA_9 = false; + JAVA_6 = false; + } + } else { + // we probably don't support anything below 1.6 or non JavaSE + JAVA_21 = false; + JAVA_17 = false; + JAVA_9 = false; + JAVA_6 = false; + } NEWLINE = System.getProperty("line.separator"); OS = System.getProperty("os.name"); @@ -177,7 +202,7 @@ public abstract class PlatformPropsImpl { final ABIType[] _elfAbiType = { null }; final int[] _elfLittleEndian = { 0 }; // 1 - little, 2 - big final boolean[] _elfValid = { false }; - AccessController.doPrivileged(new PrivilegedAction<Object>() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { RandomAccessFile in = null; @@ -353,7 +378,7 @@ public abstract class PlatformPropsImpl { private static final String getJavaRuntimeNameImpl() { // the fast path, check property Java SE instead of traversing through the ClassLoader - return AccessController.doPrivileged(new PrivilegedAction<String>() { + return SecurityUtil.doPrivileged(new PrivilegedAction<String>() { @Override public String run() { return System.getProperty("java.runtime.name"); diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java index 90a954b..bbe815d 100644 --- a/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java +++ b/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java @@ -265,7 +265,7 @@ public class TestByteBufferInputStream extends SingletonJunitCase { final long t1 = System.currentTimeMillis(); final File out = new File(fileOut); - IOUtil.copyStream2File(bis, out, -1); + IOUtil.copyStream2File(bis, out); final long t2 = System.currentTimeMillis(); final String suffix; diff --git a/src/junit/com/jogamp/common/util/IntIntHashMapTest.java b/src/junit/com/jogamp/common/util/IntIntHashMapTest.java index dc523f0..647e471 100644 --- a/src/junit/com/jogamp/common/util/IntIntHashMapTest.java +++ b/src/junit/com/jogamp/common/util/IntIntHashMapTest.java @@ -39,6 +39,7 @@ import java.util.Map.Entry; import org.junit.BeforeClass; import org.junit.Test; +import com.jogamp.common.os.Clock; import com.jogamp.common.os.Platform; import com.jogamp.junit.util.SingletonJunitCase; @@ -254,54 +255,54 @@ public class IntIntHashMapTest extends SingletonJunitCase { " warmup: " + warmup); out.println("put"); - long time = nanoTime(); + long time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { intmap.put(pairs.keys[i], pairs.values[i]); } - final long intmapPutTime = (nanoTime() - time); + final long intmapPutTime = (Clock.currentNanos() - time); out.println(" iimap: " + intmapPutTime/1000000.0f+"ms"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { map.put(pairs.keys[i], pairs.values[i]); } - final long mapPutTime = (nanoTime() - time); + final long mapPutTime = (Clock.currentNanos() - time); out.println(" map: " + mapPutTime/1000000.0f+"ms"); System.out.println(); System.out.println("get"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { intmap.get(pairs.keys[i]); } - final long intmapGetTime = (nanoTime() - time); + final long intmapGetTime = (Clock.currentNanos() - time); out.println(" iimap: " + intmapGetTime/1000000.0f+"ms"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { map.get(pairs.keys[i]); } - final long mapGetTime = (nanoTime() - time); + final long mapGetTime = (Clock.currentNanos() - time); out.println(" map: " + mapGetTime/1000000.0f+"ms"); out.println(); out.println("remove"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { intmap.remove(pairs.keys[i]); } assertEquals(0, intmap.size()); - final long intmapRemoveTime = (nanoTime() - time); + final long intmapRemoveTime = (Clock.currentNanos() - time); out.println(" iimap: " + intmapRemoveTime/1000000.0f+"ms"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { map.remove(pairs.keys[i]); } assertEquals(0, map.size()); - final long mapRemoveTime = (nanoTime() - time); + final long mapRemoveTime = (Clock.currentNanos() - time); out.println(" map: " + mapRemoveTime/1000000.0f+"ms"); if(!warmup) { diff --git a/src/junit/com/jogamp/common/util/LongIntHashMapTest.java b/src/junit/com/jogamp/common/util/LongIntHashMapTest.java index 9ea4206..60f404d 100644 --- a/src/junit/com/jogamp/common/util/LongIntHashMapTest.java +++ b/src/junit/com/jogamp/common/util/LongIntHashMapTest.java @@ -39,6 +39,7 @@ import java.util.Map.Entry; import org.junit.BeforeClass; import org.junit.Test; +import com.jogamp.common.os.Clock; import com.jogamp.common.os.Platform; import com.jogamp.junit.util.SingletonJunitCase; @@ -143,55 +144,55 @@ public class LongIntHashMapTest extends SingletonJunitCase { " warmup: " + warmup); out.println("put"); - long time = nanoTime(); + long time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { intmap.put(pairs.keys[i], pairs.values[i]); } - final long intmapPutTime = (nanoTime() - time); + final long intmapPutTime = (Clock.currentNanos() - time); out.println(" iimap: " + intmapPutTime/1000000.0f+"ms"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { map.put(pairs.keys[i], pairs.values[i]); } - final long mapPutTime = (nanoTime() - time); + final long mapPutTime = (Clock.currentNanos() - time); out.println(" map: " + mapPutTime/1000000.0f+"ms"); System.out.println(); System.out.println("get"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { intmap.get(pairs.keys[i]); } - final long intmapGetTime = (nanoTime() - time); + final long intmapGetTime = (Clock.currentNanos() - time); out.println(" iimap: " + intmapGetTime/1000000.0f+"ms"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { map.get(pairs.keys[i]); } - final long mapGetTime = (nanoTime() - time); + final long mapGetTime = (Clock.currentNanos() - time); out.println(" map: " + mapGetTime/1000000.0f+"ms"); out.println(); out.println("remove"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { intmap.remove(pairs.keys[i]); } assertEquals(0, intmap.size()); - final long intmapRemoveTime = (nanoTime() - time); + final long intmapRemoveTime = (Clock.currentNanos() - time); out.println(" iimap: " + intmapRemoveTime/1000000.0f+"ms"); - time = nanoTime(); + time = Clock.currentNanos(); for (int i = 0; i < iterations; i++) { map.remove(pairs.keys[i]); } assertEquals(0, map.size()); - final long mapRemoveTime = (nanoTime() - time); + final long mapRemoveTime = (Clock.currentNanos() - time); out.println(" map: " + mapRemoveTime/1000000.0f+"ms"); if(!warmup) { diff --git a/src/junit/com/jogamp/common/util/TestIOUtil01.java b/src/junit/com/jogamp/common/util/TestIOUtil01.java index 19bc8b0..c0e26a9 100644 --- a/src/junit/com/jogamp/common/util/TestIOUtil01.java +++ b/src/junit/com/jogamp/common/util/TestIOUtil01.java @@ -221,6 +221,118 @@ public class TestIOUtil01 extends SingletonJunitCase { } } + @Test + public void test21CopyStreamChunk01Buffer() throws IOException { + final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass()); + Assert.assertNotNull(urlConn); + final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() ); + final ByteBuffer bb; + final int skipBytes = 0; + final int byteCount = orig.length; + try { + bb = IOUtil.copyStreamChunk2ByteBuffer( bis, skipBytes, byteCount ); + } finally { + IOUtil.close(bis, false); + } + Assert.assertTrue( machine.pageAlignedSize( byteCount ) >= byteCount ); + Assert.assertEquals( machine.pageAlignedSize( byteCount ), bb.capacity() ); + Assert.assertEquals(orig.length, bb.limit()); + int i; + for(i=tsz-1; i>=0 && orig[i]==bb.get(i); i--) ; + Assert.assertTrue("Bytes not equal orig vs array", 0>i); + System.err.println(getTestMethodName()+" OK: ["+skipBytes+".."+(skipBytes+byteCount)+"): "+bb); + } + + @Test + public void test22CopyStreamChunk02Buffer() throws IOException { + final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass()); + Assert.assertNotNull(urlConn); + final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() ); + final ByteBuffer bb; + final int skipBytes = 0; + final int byteCount = orig.length + machine.pageSizeInBytes(); // expect more data than exists, complete with actual data + try { + bb = IOUtil.copyStreamChunk2ByteBuffer( bis, skipBytes, byteCount ); + } finally { + IOUtil.close(bis, false); + } + Assert.assertTrue( machine.pageAlignedSize( byteCount ) >= byteCount ); + Assert.assertEquals( machine.pageAlignedSize( byteCount ), bb.capacity() ); + Assert.assertEquals( orig.length, bb.limit() ); + int i; + for(i=tsz-1; i>=0 && orig[i]==bb.get(i); i--) ; + Assert.assertTrue("Bytes not equal orig vs array", 0>i); + System.err.println(getTestMethodName()+" OK: ["+skipBytes+".."+(skipBytes+byteCount)+"): "+bb); + } + + @Test + public void test23CopyStreamChunk03Buffer() throws IOException { + final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass()); + Assert.assertNotNull(urlConn); + final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() ); + final ByteBuffer bb; + final int skipBytes = 0; + final int byteCount = orig.length / 2; // take less data than exists + Assert.assertTrue( orig.length >= byteCount ); + try { + bb = IOUtil.copyStreamChunk2ByteBuffer( bis, skipBytes, byteCount ); + } finally { + IOUtil.close(bis, false); + } + Assert.assertTrue( machine.pageAlignedSize( byteCount ) >= byteCount ); + Assert.assertEquals( machine.pageAlignedSize( byteCount ), bb.capacity() ); + Assert.assertEquals( byteCount, bb.limit() ); + int i; + for(i=byteCount-1; i>=0 && orig[i]==bb.get(i); i--) ; + Assert.assertTrue("Bytes not equal orig vs array", 0>i); + System.err.println(getTestMethodName()+" OK: ["+skipBytes+".."+(skipBytes+byteCount)+"): "+bb); + } + + @Test + public void test24CopyStreamChunk04Buffer() throws IOException { + final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass()); + Assert.assertNotNull(urlConn); + final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() ); + final ByteBuffer bb; + final int skipBytes = orig.length / 2; + final int byteCount = orig.length / 4; // take less data than exists + Assert.assertTrue( orig.length >= skipBytes + byteCount ); + Assert.assertTrue( orig.length >= byteCount ); + try { + bb = IOUtil.copyStreamChunk2ByteBuffer( bis, skipBytes, byteCount ); + } finally { + IOUtil.close(bis, false); + } + Assert.assertTrue( machine.pageAlignedSize( byteCount ) >= byteCount ); + Assert.assertEquals( machine.pageAlignedSize( byteCount ), bb.capacity() ); + Assert.assertEquals( byteCount, bb.limit() ); + int i; + for(i=byteCount-1; i>=0 && orig[skipBytes+i]==bb.get(i); i--) ; + Assert.assertTrue("Bytes not equal orig vs array", 0>i); + System.err.println(getTestMethodName()+" OK: ["+skipBytes+".."+(skipBytes+byteCount)+"): "+bb); + } + + @Test + public void test25CopyStreamChunk05Buffer() throws IOException { + final URLConnection urlConn = IOUtil.getResource(tfilename, this.getClass().getClassLoader(), this.getClass()); + Assert.assertNotNull(urlConn); + final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() ); + final ByteBuffer bb; + final int skipBytes = orig.length * 2; // skip all and more .. + final int byteCount = orig.length; // expect more data than left, won't take anything + Assert.assertTrue( orig.length < skipBytes + byteCount ); + Assert.assertTrue( orig.length >= byteCount ); + try { + bb = IOUtil.copyStreamChunk2ByteBuffer( bis, skipBytes, byteCount ); + } finally { + IOUtil.close(bis, false); + } + Assert.assertTrue( machine.pageAlignedSize( byteCount ) >= byteCount ); + Assert.assertEquals( machine.pageAlignedSize( byteCount ), bb.capacity() ); + Assert.assertEquals( 0, bb.limit() ); + System.err.println(getTestMethodName()+" OK: ["+skipBytes+".."+(skipBytes+byteCount)+"): "+bb); + } + public static void main(final String args[]) throws IOException { final String tstname = TestIOUtil01.class.getName(); org.junit.runner.JUnitCore.main(tstname); diff --git a/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java b/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java index 8289587..70cb06b 100644 --- a/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java +++ b/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java @@ -45,7 +45,7 @@ public class TestIteratorIndexCORE extends SingletonJunitCase { static int elems = 10; static int loop = ( Platform.getCPUFamily() == Platform.CPUFamily.ARM ) ? 20 : 9999999; - public void populate(final List l, int len) { + public void populate(final List<Integer> l, int len) { while(len>0) { l.add(new Integer(len--)); } @@ -54,12 +54,12 @@ public class TestIteratorIndexCORE extends SingletonJunitCase { @Test public void test01ArrayListIterator() { int sum=0; - final ArrayList l = new ArrayList(); + final ArrayList<Integer> l = new ArrayList<Integer>(); populate(l, elems); for(int j=loop; j>0; j--) { - for(final Iterator iter = l.iterator(); iter.hasNext(); ) { - final Integer i = (Integer)iter.next(); + for(final Iterator<Integer> iter = l.iterator(); iter.hasNext(); ) { + final Integer i = iter.next(); sum+=i.intValue(); } } @@ -69,12 +69,12 @@ public class TestIteratorIndexCORE extends SingletonJunitCase { @Test public void test0ArrayListIndex() { int sum=0; - final ArrayList l = new ArrayList(); + final ArrayList<Integer> l = new ArrayList<Integer>(); populate(l, elems); for(int j=loop; j>0; j--) { for(int k = 0; k < l.size(); k++) { - final Integer i = (Integer)l.get(k); + final Integer i = l.get(k); sum+=i.intValue(); } } @@ -84,12 +84,12 @@ public class TestIteratorIndexCORE extends SingletonJunitCase { @Test public void test01LinkedListListIterator() { int sum=0; - final LinkedList l = new LinkedList(); + final LinkedList<Integer> l = new LinkedList<Integer>(); populate(l, elems); for(int j=loop; j>0; j--) { - for(final Iterator iter = l.iterator(); iter.hasNext(); ) { - final Integer i = (Integer)iter.next(); + for(final Iterator<Integer> iter = l.iterator(); iter.hasNext(); ) { + final Integer i = iter.next(); sum+=i.intValue(); } } @@ -99,12 +99,12 @@ public class TestIteratorIndexCORE extends SingletonJunitCase { @Test public void test01LinkedListListIndex() { int sum=0; - final LinkedList l = new LinkedList(); + final LinkedList<Integer> l = new LinkedList<Integer>(); populate(l, elems); for(int j=loop; j>0; j--) { for(int k = 0; k < l.size(); k++) { - final Integer i = (Integer)l.get(k); + final Integer i = l.get(k); sum+=i.intValue(); } } diff --git a/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java b/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java index 7455618..e119569 100644 --- a/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java +++ b/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java @@ -37,6 +37,7 @@ import java.util.Map; import org.junit.Assert; import org.junit.Test; +import com.jogamp.common.os.Clock; import com.jogamp.common.os.Platform; import com.jogamp.common.util.InterruptSource; import com.jogamp.junit.util.SingletonJunitCase; @@ -57,7 +58,7 @@ public class TestRecursiveLock01 extends SingletonJunitCase { } } - static void yield(final YieldMode mode) { + static void yield_thread(final YieldMode mode) { switch(mode) { case YIELD: Thread.yield(); @@ -119,7 +120,7 @@ public class TestRecursiveLock01 extends SingletonJunitCase { System.err.print("+"); } while(l>0) l--; - yield(yieldMode); + yield_thread(yieldMode); } finally { if(DEBUG) { System.err.print("-"); @@ -141,6 +142,7 @@ public class TestRecursiveLock01 extends SingletonJunitCase { incrDeferredThreadCount(); } + @Override public void run() { if(DEBUG) { System.err.print("[a2"); @@ -151,7 +153,7 @@ public class TestRecursiveLock01 extends SingletonJunitCase { System.err.print("+"); } while(l>0) l--; - yield(yieldMode); + yield_thread(yieldMode); } finally { if(DEBUG) { System.err.print("-"); @@ -175,9 +177,9 @@ public class TestRecursiveLock01 extends SingletonJunitCase { } public final void lock() { - long td = System.nanoTime(); + long td = Clock.currentNanos(); locker.lock(); - td = System.nanoTime() - td; + td = Clock.currentNanos() - td; final String cur = Thread.currentThread().getName(); ThreadStat ts = threadWaitMap.get(cur); @@ -258,14 +260,17 @@ public class TestRecursiveLock01 extends SingletonJunitCase { this.yieldMode = yieldMode; } + @Override public final void stop() { shouldStop = true; } + @Override public final boolean isStopped() { return stopped; } + @Override public void waitUntilStopped() { synchronized(this) { while(!stopped) { @@ -279,6 +284,7 @@ public class TestRecursiveLock01 extends SingletonJunitCase { } + @Override public void run() { synchronized(this) { while(!shouldStop && loops>0) { diff --git a/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java b/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java index 30a0274..3cd40dd 100644 --- a/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java +++ b/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java @@ -53,7 +53,7 @@ public class TestRecursiveThreadGroupLock01 extends SingletonJunitCase { } } - static void yield(final YieldMode mode) { + static void yield_thread(final YieldMode mode) { switch(mode) { case YIELD: Thread.yield(); @@ -96,7 +96,7 @@ public class TestRecursiveThreadGroupLock01 extends SingletonJunitCase { slaves[i].start(); } while(slaveCounter<mark) { - yield(yieldMode); + yield_thread(yieldMode); } } } finally { @@ -130,7 +130,7 @@ public class TestRecursiveThreadGroupLock01 extends SingletonJunitCase { while(slaveCounter<mark) { slaveCounter++; } */ - yield(yieldMode); + yield_thread(yieldMode); } finally { if(DEBUG) { System.err.println(tab+" "+name+" c "+slaveCounter+"]"); diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/BindingJNILibLoader.java b/src/junit/com/jogamp/gluegen/test/junit/generation/BindingJNILibLoader.java index 47e392a..6b841ad 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/BindingJNILibLoader.java +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/BindingJNILibLoader.java @@ -29,27 +29,31 @@ package com.jogamp.gluegen.test.junit.generation; import com.jogamp.common.jvm.JNILibLoaderBase; +import com.jogamp.common.util.SecurityUtil; + import java.security.*; public class BindingJNILibLoader extends JNILibLoaderBase { - public static void loadBindingtest1p1() { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - loadLibrary("Bindingtest1p1", null, true, BindingJNILibLoader.class.getClassLoader()); - return null; - } - }); - } - - public static void loadBindingtest1p2() { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - loadLibrary("Bindingtest1p2", null, true, BindingJNILibLoader.class.getClassLoader()); - return null; - } - }); - } + public static void loadBindingtest1p1() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + loadLibrary("Bindingtest1p1", null, true, BindingJNILibLoader.class.getClassLoader()); + return null; + } + }); + } + + public static void loadBindingtest1p2() { + SecurityUtil.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + loadLibrary("Bindingtest1p2", null, true, BindingJNILibLoader.class.getClassLoader()); + return null; + } + }); + } } diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h index 4896165..9465cd9 100644 --- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h +++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h @@ -299,8 +299,8 @@ MYAPI MYAPIConfig * MYAPIENTRY typeTestAnonPointer(const MYAPIConfig * a); #define HUGE_VALF_3 ((int) 1e53) #define DOUBLE_DEFINE_BRACKETS_3 HUGE_VALF_3 -size_t unsigned_size_t_1; -ptrdiff_t a_signed_pointer_t_1; +extern size_t unsigned_size_t_1; +extern ptrdiff_t a_signed_pointer_t_1; MYAPI int32_t MYAPIENTRY typeTestInt32T(const int32_t i1, int32_t i2); MYAPI uint32_t MYAPIENTRY typeTestUInt32T(const uint32_t ui1, uint32_t ui2); @@ -462,8 +462,8 @@ typedef struct { TK_Context ctx; - const char modelNameArrayFixedLen[12]; /* 'Hello Array' len=11+1 */ - const char * modelNamePointerCString; /* 'Hello CString' len=13+1 */ + char modelNameArrayFixedLen[12]; /* 'Hello Array' len=11+1 */ + char * modelNamePointerCString; /* 'Hello CString' len=13+1 */ const char * modelNamePointerCustomLen; /* 'Hello Pointer' len=13+1 */ const int modelNamePointerCustomLenVal; /* 13+1 */ @@ -495,7 +495,7 @@ typedef struct { TK_Context ctx; char modelNameArrayFixedLen[12]; /* 'Hello Array' len=11+1 */ - const char * modelNamePointerCString; /* 'Hello CString' len=13+1 */ + char * modelNamePointerCString; /* 'Hello CString' len=13+1 */ char * modelNamePointerCustomLen; /* 'Hello Pointer' len=13+1 */ int modelNamePointerCustomLenVal; /* 13+1 */ diff --git a/src/junit/com/jogamp/junit/util/MiscUtils.java b/src/junit/com/jogamp/junit/util/MiscUtils.java index 3576fed..03d4d13 100644 --- a/src/junit/com/jogamp/junit/util/MiscUtils.java +++ b/src/junit/com/jogamp/junit/util/MiscUtils.java @@ -103,7 +103,7 @@ public class MiscUtils { } final InputStream in = new BufferedInputStream(new FileInputStream(src)); try { - stats.totalBytes += IOUtil.copyStream2File(in, dest, 0); + stats.totalBytes += IOUtil.copyStream2File(in, dest); } finally { in.close(); } diff --git a/src/native/common/Platforms.c b/src/native/common/Platforms.c deleted file mode 100644 index f48d020..0000000 --- a/src/native/common/Platforms.c +++ /dev/null @@ -1,25 +0,0 @@ - -#include <jni.h> - -#include <assert.h> - -#include <gluegen_stdint.h> - -#include "com_jogamp_common_os_Platform.h" - -#include <sys/time.h> - -JNIEXPORT jlong JNICALL -Java_com_jogamp_common_os_Platform_currentTimeMillis(JNIEnv *env, jclass _unused) { - struct timeval tv; - gettimeofday(&tv,NULL); - return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -JNIEXPORT jlong JNICALL -Java_com_jogamp_common_os_Platform_currentTimeMicros(JNIEnv *env, jclass _unused) { - struct timeval tv; - gettimeofday(&tv,NULL); - return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; -} - diff --git a/src/native/common/jau_sys_Clock.c b/src/native/common/jau_sys_Clock.c new file mode 100644 index 0000000..e8a7210 --- /dev/null +++ b/src/native/common/jau_sys_Clock.c @@ -0,0 +1,292 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020-2023 Gothel Software e.K. + * Copyright (c) 2020-2023 JogAmp Community. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <jni.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <assert.h> + +#include <gluegen_stdint.h> + +#include "com_jogamp_common_os_Clock.h" + +#include <time.h> + +#if defined(_WIN32) + #include <windows.h> + #ifndef IN_WINPTHREAD + #define IN_WINPTHREAD 1 + #endif + #include "pthread.h" + #include "pthread_time.h" +#endif + +static const int64_t NanoPerMilli = 1000000L; +static const int64_t MilliPerOne = 1000L; +static const int64_t NanoPerSec = 1000000000L; + +static struct timespec startup_t = { .tv_sec = 0, .tv_nsec = 0 }; + +static void throwNewRuntimeException(JNIEnv *env, const char* msg, ...) { + char buffer[512]; + va_list ap; + + if( NULL != msg ) { + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); + + fprintf(stderr, "RuntimeException: %s\n", buffer); + if(NULL != env) { + (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), buffer); + } + } +} + +static jboolean throwNewRuntimeExceptionOnException(JNIEnv *env) { + if( (*env)->ExceptionCheck(env) ) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + throwNewRuntimeException(env, "An exception occured from JNI as shown."); + return JNI_TRUE; + } else { + return JNI_FALSE; + } +} + + +JNIEXPORT jboolean JNICALL +Java_com_jogamp_common_os_Clock_getMonotonicTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) { + (void)clazz; + + // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime() + struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; + int res = clock_gettime(CLOCK_MONOTONIC, &t); + const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec }; + (*env)->SetLongArrayRegion(env, jval, 0, 2, val); + return 0 == res ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_com_jogamp_common_os_Clock_getWallClockTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) { + (void)clazz; + + // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime() + struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; + int res = clock_gettime(CLOCK_REALTIME, &t); + const jlong val[] = { (jlong)t.tv_sec, (jlong)t.tv_nsec }; + (*env)->SetLongArrayRegion(env, jval, 0, 2, val); + return 0 == res ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_com_jogamp_common_os_Clock_getMonotonicStartupTimeImpl(JNIEnv *env, jclass clazz, jlongArray jval) { + (void)clazz; + + // Avoid GetPrimitiveArrayCritical(), which occasionally hangs on system call ::clock_gettime() + int res = clock_gettime(CLOCK_MONOTONIC, &startup_t); + const jlong val[] = { (jlong)startup_t.tv_sec, (jlong)startup_t.tv_nsec }; + (*env)->SetLongArrayRegion(env, jval, 0, 2, val); + if( throwNewRuntimeExceptionOnException(env) ) { + return JNI_FALSE; + } + return 0 == res ? JNI_TRUE : JNI_FALSE; +} + +/** + * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html> + * <p> + * Regarding avoiding kernel via VDSO, + * see <http://man7.org/linux/man-pages/man7/vdso.7.html>, + * clock_gettime seems to be well supported at least on kernel >= 4.4. + * Only bfin and sh are missing, while ia64 seems to be complicated. + */ +JNIEXPORT jlong JNICALL +Java_com_jogamp_common_os_Clock_currentNanos(JNIEnv *env, jclass clazz) { + (void)env; + (void)clazz; + + struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; + if( 0 == clock_gettime(CLOCK_MONOTONIC, &t) ) { + struct timespec d = { .tv_sec = t.tv_sec - startup_t.tv_sec, + .tv_nsec = t.tv_nsec - startup_t.tv_nsec }; + if ( 0 > d.tv_nsec ) { + d.tv_nsec += NanoPerSec; + d.tv_sec -= 1; + } + return (jlong) ( (int64_t)d.tv_sec * NanoPerSec + (int64_t)d.tv_nsec ); + } else { + return 0; + } +} + +/** + * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html> + * <p> + * Regarding avoiding kernel via VDSO, + * see <http://man7.org/linux/man-pages/man7/vdso.7.html>, + * clock_gettime seems to be well supported at least on kernel >= 4.4. + * Only bfin and sh are missing, while ia64 seems to be complicated. + */ +JNIEXPORT jlong JNICALL +Java_com_jogamp_common_os_Clock_currentTimeMillis(JNIEnv *env, jclass clazz) { + (void)env; + (void)clazz; + + struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; + if( 0 == clock_gettime(CLOCK_MONOTONIC, &t) ) { + int64_t res = (int64_t)t.tv_sec * MilliPerOne + + (int64_t)t.tv_nsec / NanoPerMilli; + return (jlong)res; + } else { + return 0; + } +} + +JNIEXPORT jlong JNICALL +Java_com_jogamp_common_os_Clock_wallClockSeconds(JNIEnv *env, jclass clazz) { + (void)env; + (void)clazz; + + struct timespec t = { .tv_sec = 0, .tv_nsec = 0 }; + if( 0 == clock_gettime(CLOCK_REALTIME, &t) ) { + return (jlong)( (int64_t)( t.tv_sec ) ); + } else { + return 0; + } +} + +#if defined(_WIN32) + +#define POW10_7 10000000 +#define POW10_9 1000000000 + +/* Number of 100ns-seconds between the beginning of the Windows epoch + * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970) + */ +#define DELTA_EPOCH_IN_100NS INT64_C(116444736000000000) + +static WINPTHREADS_INLINE int lc_set_errno(int result) +{ + if (result != 0) { + errno = result; + return -1; + } + return 0; +} + +/** + * Source: https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-libraries/winpthreads/src/clock.c + * Public Domain within mingw-w64, included here to simplify linkage. + * + * Get the time of the specified clock clock_id and stores it in the struct + * timespec pointed to by tp. + * @param clock_id The clock_id argument is the identifier of the particular + * clock on which to act. The following clocks are supported: + * <pre> + * CLOCK_REALTIME System-wide real-time clock. Setting this clock + * requires appropriate privileges. + * CLOCK_MONOTONIC Clock that cannot be set and represents monotonic + * time since some unspecified starting point. + * CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU. + * CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock. + * </pre> + * @param tp The pointer to a timespec structure to receive the time. + * @return If the function succeeds, the return value is 0. + * If the function fails, the return value is -1, + * with errno set to indicate the error. + */ +int clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + unsigned __int64 t; + LARGE_INTEGER pf, pc; + union { + unsigned __int64 u64; + FILETIME ft; + } ct, et, kt, ut; + + switch(clock_id) { + case CLOCK_REALTIME: + { + GetSystemTimeAsFileTime(&ct.ft); + t = ct.u64 - DELTA_EPOCH_IN_100NS; + tp->tv_sec = t / POW10_7; + tp->tv_nsec = ((int) (t % POW10_7)) * 100; + + return 0; + } + + case CLOCK_MONOTONIC: + { + if (QueryPerformanceFrequency(&pf) == 0) + return lc_set_errno(EINVAL); + + if (QueryPerformanceCounter(&pc) == 0) + return lc_set_errno(EINVAL); + + tp->tv_sec = pc.QuadPart / pf.QuadPart; + tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart); + if (tp->tv_nsec >= POW10_9) { + tp->tv_sec ++; + tp->tv_nsec -= POW10_9; + } + + return 0; + } + + case CLOCK_PROCESS_CPUTIME_ID: + { + if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft)) + return lc_set_errno(EINVAL); + t = kt.u64 + ut.u64; + tp->tv_sec = t / POW10_7; + tp->tv_nsec = ((int) (t % POW10_7)) * 100; + + return 0; + } + + case CLOCK_THREAD_CPUTIME_ID: + { + if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft)) + return lc_set_errno(EINVAL); + t = kt.u64 + ut.u64; + tp->tv_sec = t / POW10_7; + tp->tv_nsec = ((int) (t % POW10_7)) * 100; + + return 0; + } + + default: + break; + } + + return lc_set_errno(EINVAL); +} + +#endif + |