mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-19 06:51:42 +01:00
Compare commits
94 Commits
jbr21.992
...
avu/ISO_BL
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da19b1c201 | ||
|
|
06cc75d80b | ||
|
|
203aad0e7d | ||
|
|
fa662e668a | ||
|
|
f4eed0aabf | ||
|
|
c43a8e77a9 | ||
|
|
44c769baf2 | ||
|
|
d65e4f3a69 | ||
|
|
01a88fa82d | ||
|
|
224651121f | ||
|
|
333dbcb00f | ||
|
|
c874bfb819 | ||
|
|
f14bfe0de9 | ||
|
|
e948e68a1c | ||
|
|
a40497a1a1 | ||
|
|
221844284c | ||
|
|
8ce1865667 | ||
|
|
dfa2f93ded | ||
|
|
a70d004636 | ||
|
|
bcaea044f6 | ||
|
|
62e4696d1a | ||
|
|
3dd9b5b323 | ||
|
|
9d1557ed3c | ||
|
|
b6f8f9f1b7 | ||
|
|
548521e162 | ||
|
|
633895e1d8 | ||
|
|
fdc9dd44b6 | ||
|
|
677d8edb87 | ||
|
|
52b213d96c | ||
|
|
df366c74c1 | ||
|
|
fc40612222 | ||
|
|
8b7153234f | ||
|
|
26f247ffb3 | ||
|
|
aa20c8b9f4 | ||
|
|
120dd88dd0 | ||
|
|
bb371ce7b0 | ||
|
|
abbf53d08e | ||
|
|
921053cda6 | ||
|
|
1b0348f1b9 | ||
|
|
8120022a66 | ||
|
|
ac68b628c7 | ||
|
|
99d3227951 | ||
|
|
9116f5b953 | ||
|
|
13ddb27c38 | ||
|
|
6e0ea66116 | ||
|
|
f6b0380fd9 | ||
|
|
70a658f57a | ||
|
|
8fd5f9c426 | ||
|
|
03cf016f2d | ||
|
|
1e1e4b38c6 | ||
|
|
3b4da58e2c | ||
|
|
1b439f8a98 | ||
|
|
4516560f65 | ||
|
|
4a94eadd90 | ||
|
|
42db39fb4e | ||
|
|
cb751d0b52 | ||
|
|
f711061895 | ||
|
|
6d0eb24888 | ||
|
|
3c90ecd46c | ||
|
|
54817b2e8d | ||
|
|
c70e17b88b | ||
|
|
bcd6f0c9c0 | ||
|
|
646d2e478f | ||
|
|
4214897d5e | ||
|
|
189907d2ae | ||
|
|
4b17fcc46e | ||
|
|
03804770b6 | ||
|
|
1d0cbadf05 | ||
|
|
8cfd55e764 | ||
|
|
b06068de9c | ||
|
|
eb027e2bc9 | ||
|
|
5fbd7f38e0 | ||
|
|
44754c75f9 | ||
|
|
0bf04b04b0 | ||
|
|
ca69af5c29 | ||
|
|
1527cb78dd | ||
|
|
bd8b5fa16f | ||
|
|
c53afaf1c6 | ||
|
|
81b393aa37 | ||
|
|
8b4249aa00 | ||
|
|
a8b4f08808 | ||
|
|
88532ca2e1 | ||
|
|
4b01cab791 | ||
|
|
971aaf09d7 | ||
|
|
219ad23c66 | ||
|
|
20015bc3b7 | ||
|
|
20bfe049b3 | ||
|
|
e32b9d4ebc | ||
|
|
8ec3e80317 | ||
|
|
c1325a3735 | ||
|
|
cc2280fd08 | ||
|
|
af4d8df355 | ||
|
|
8fe8fb8108 | ||
|
|
997c61fdc5 |
@@ -40,8 +40,6 @@ architecture=${3:-x64} # aarch64 or x64
|
||||
|
||||
check_bundle_type_maketest
|
||||
|
||||
tag_prefix="jbr-"
|
||||
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "$tag_prefix" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -g | tail -n 1 | tr -d ",")
|
||||
VERSION_FEATURE=$(getVersionProp "DEFAULT_VERSION_FEATURE")
|
||||
VERSION_INTERIM=$(getVersionProp "DEFAULT_VERSION_INTERIM")
|
||||
VERSION_UPDATE=$(getVersionProp "DEFAULT_VERSION_UPDATE")
|
||||
@@ -49,8 +47,15 @@ VERSION_PATCH=$(getVersionProp "DEFAULT_VERSION_PATCH")
|
||||
[[ $VERSION_UPDATE = 0 ]] && JBSDK_VERSION="$VERSION_FEATURE" || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}"
|
||||
[[ $VERSION_PATCH = 0 ]] || JBSDK_VERSION="${VERSION_FEATURE}.${VERSION_INTERIM}.${VERSION_UPDATE}.${VERSION_PATCH}"
|
||||
echo "##teamcity[setParameter name='env.JBSDK_VERSION' value='${JBSDK_VERSION}']"
|
||||
JDK_BUILD_NUMBER=${JDK_BUILD_NUMBER:=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $3}')}
|
||||
tag_prefix="jbr-"
|
||||
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "${tag_prefix}${JBSDK_VERSION}" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -V -f | tail -n 1 | tr -d ",")
|
||||
JDK_BUILD_NUMBER=$(echo $OPENJDK_TAG | awk -F "-|[+]" '{print $3}')
|
||||
[ -z $JDK_BUILD_NUMBER ] && JDK_BUILD_NUMBER=1
|
||||
re='^[0-9]+$'
|
||||
if ! [[ $JDK_BUILD_NUMBER =~ $re ]] ; then
|
||||
echo "error: JDK_BUILD_NUMBER Not a number: $JDK_BUILD_NUMBER"
|
||||
JDK_BUILD_NUMBER=1
|
||||
fi
|
||||
echo "##teamcity[setParameter name='env.JDK_UPDATE_NUMBER' value='${JDK_BUILD_NUMBER}']"
|
||||
|
||||
VENDOR_NAME="JetBrains s.r.o."
|
||||
|
||||
@@ -32,6 +32,13 @@ function do_configure {
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--openjdk-target=x86_64-unknown-linux-gnu"
|
||||
fi
|
||||
|
||||
if [ -n "${JCEF_BUILD_LEGACY:-}" ]; then
|
||||
WITH_VULKAN=""
|
||||
else
|
||||
WITH_VULKAN="--with-vulkan"
|
||||
fi
|
||||
|
||||
sh configure \
|
||||
$WITH_DEBUG_LEVEL \
|
||||
--with-vendor-name="$VENDOR_NAME" \
|
||||
@@ -42,7 +49,7 @@ function do_configure {
|
||||
--with-version-opt=b"$build_number" \
|
||||
--with-boot-jdk="$BOOT_JDK" \
|
||||
--enable-cds=yes \
|
||||
--with-vulkan \
|
||||
$WITH_VULKAN \
|
||||
$LINUX_TARGET \
|
||||
$DISABLE_WARNINGS_AS_ERRORS \
|
||||
$STATIC_CONF_ARGS \
|
||||
@@ -95,7 +102,9 @@ function create_image_bundle {
|
||||
|
||||
# jmod does not preserve file permissions (JDK-8173610)
|
||||
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/jcef_helper ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/jcef_helper
|
||||
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/cef_server ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/cef_server
|
||||
if [ ! -n "${JCEF_BUILD_LEGACY:-}" ]; then
|
||||
[ -f "$IMAGES_DIR"/"$__root_dir"/lib/cef_server ] && chmod a+x "$IMAGES_DIR"/"$__root_dir"/lib/cef_server
|
||||
fi
|
||||
|
||||
echo Creating "$JBR".tar.gz ...
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ set -x
|
||||
#
|
||||
|
||||
source jb/project/tools/common/scripts/common.sh
|
||||
ENABLE_CDS="no"
|
||||
|
||||
function do_configure {
|
||||
linux32 bash configure \
|
||||
@@ -24,7 +25,7 @@ function do_configure {
|
||||
--with-version-opt=b"$build_number" \
|
||||
--with-boot-jdk="$BOOT_JDK" \
|
||||
$STATIC_CONF_ARGS \
|
||||
--enable-cds=yes \
|
||||
--enable-cds=$ENABLE_CDS \
|
||||
$DISABLE_WARNINGS_AS_ERRORS \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
$WITH_ZIPPED_NATIVE_DEBUG_SYMBOLS \
|
||||
@@ -51,7 +52,7 @@ function create_image_bundle {
|
||||
__cds_opt=''
|
||||
|
||||
if is_musl; then libc_type_suffix='musl-' ; fi
|
||||
__cds_opt="--generate-cds-archive"
|
||||
[ "${ENABLE_CDS}" == "yes" ] && __cds_opt="--generate-cds-archive"
|
||||
|
||||
[ "$bundle_type" == "fd" ] && [ "$__arch_name" == "$JBRSDK_BUNDLE" ] && __bundle_name=$__arch_name && fastdebug_infix="fastdebug-"
|
||||
JBR=${__bundle_name}-${JBSDK_VERSION}-linux-${libc_type_suffix}x86-${fastdebug_infix}b${build_number}
|
||||
|
||||
267
jb/project/tools/perf/j2dbopts_poly250-AA-rand_col.txt
Normal file
267
jb/project/tools/perf/j2dbopts_poly250-AA-rand_col.txt
Normal file
@@ -0,0 +1,267 @@
|
||||
prog.verbose=disabled
|
||||
prog.printresults=enabled
|
||||
global.env.outputwidth=640
|
||||
global.env.outputheight=480
|
||||
global.env.runcount=5
|
||||
global.env.repcount=0
|
||||
global.env.testtime=2500
|
||||
global.results.workunits=units
|
||||
global.results.timeunits=sec
|
||||
global.results.ratio=unitspersec
|
||||
global.dest.offscreen=disabled
|
||||
global.dest.frame.defaultframe=enabled
|
||||
global.dest.frame.transframe=disabled
|
||||
global.dest.frame.shapedframe=disabled
|
||||
global.dest.frame.shapedtransframe=disabled
|
||||
global.dest.compatimg.compatimg=disabled
|
||||
global.dest.compatimg.opqcompatimg=disabled
|
||||
global.dest.compatimg.bmcompatimg=disabled
|
||||
global.dest.compatimg.transcompatimg=disabled
|
||||
global.dest.volimg.volimg=disabled
|
||||
global.dest.volimg.opqvolimg=disabled
|
||||
global.dest.volimg.bmvolimg=disabled
|
||||
global.dest.volimg.transvolimg=disabled
|
||||
global.dest.bufimg.IntXrgb=disabled
|
||||
global.dest.bufimg.IntArgb=disabled
|
||||
global.dest.bufimg.IntArgbPre=disabled
|
||||
global.dest.bufimg.3ByteBgr=disabled
|
||||
global.dest.bufimg.ByteIndexed=disabled
|
||||
global.dest.bufimg.ByteGray=disabled
|
||||
global.dest.bufimg.4ByteAbgr=disabled
|
||||
global.dest.bufimg.4ByteAbgrPre=disabled
|
||||
global.dest.bufimg.custom=disabled
|
||||
graphics.opts.anim=2
|
||||
graphics.opts.sizes=250
|
||||
graphics.opts.alpharule=SrcOver
|
||||
graphics.opts.transform=ident
|
||||
graphics.opts.extraalpha=Off
|
||||
graphics.opts.xormode=Off
|
||||
graphics.opts.clip=Off
|
||||
graphics.opts.renderhint=Default
|
||||
graphics.render.opts.paint=random
|
||||
graphics.render.opts.alphacolor=Off
|
||||
graphics.render.opts.antialias=On
|
||||
graphics.render.opts.stroke=width1
|
||||
graphics.render.tests.drawLine=disabled
|
||||
graphics.render.tests.drawLineHoriz=disabled
|
||||
graphics.render.tests.drawLineVert=disabled
|
||||
graphics.render.tests.fillRect=disabled
|
||||
graphics.render.tests.drawRect=disabled
|
||||
graphics.render.tests.fillOval=disabled
|
||||
graphics.render.tests.drawOval=disabled
|
||||
graphics.render.tests.fillPoly=disabled
|
||||
graphics.render.tests.drawPoly=enabled
|
||||
graphics.render.tests.shape.fillCubic=disabled
|
||||
graphics.render.tests.shape.drawCubic=disabled
|
||||
graphics.render.tests.shape.fillEllipse2D=disabled
|
||||
graphics.render.tests.shape.drawEllipse2D=disabled
|
||||
graphics.imaging.src.offscr.opaque=disabled
|
||||
graphics.imaging.src.offscr.bitmask=disabled
|
||||
graphics.imaging.src.offscr.translucent=disabled
|
||||
graphics.imaging.src.opqcompatimg.opaque=disabled
|
||||
graphics.imaging.src.opqcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.opqcompatimg.translucent=disabled
|
||||
graphics.imaging.src.bmcompatimg.opaque=disabled
|
||||
graphics.imaging.src.bmcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.bmcompatimg.translucent=disabled
|
||||
graphics.imaging.src.transcompatimg.opaque=disabled
|
||||
graphics.imaging.src.transcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.transcompatimg.translucent=disabled
|
||||
graphics.imaging.src.opqvolimg.opaque=disabled
|
||||
graphics.imaging.src.opqvolimg.bitmask=disabled
|
||||
graphics.imaging.src.opqvolimg.translucent=disabled
|
||||
graphics.imaging.src.bmvolimg.opaque=disabled
|
||||
graphics.imaging.src.bmvolimg.bitmask=disabled
|
||||
graphics.imaging.src.bmvolimg.translucent=disabled
|
||||
graphics.imaging.src.transvolimg.opaque=disabled
|
||||
graphics.imaging.src.transvolimg.bitmask=disabled
|
||||
graphics.imaging.src.transvolimg.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.opaque=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.translucent=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.translucent=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.translucent=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.opaque=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.translucent=disabled
|
||||
graphics.imaging.benchmarks.opts.interpolation=Nearest neighbor
|
||||
graphics.imaging.benchmarks.opts.touchsrc=Off
|
||||
graphics.imaging.benchmarks.tests.drawimage=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagebg=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescaleup=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescaledown=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescalesplit=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagetxform=disabled
|
||||
graphics.imaging.imageops.opts.op=convolve3x3zero
|
||||
graphics.imaging.imageops.tests.graphics2d.drawimageop=disabled
|
||||
graphics.imaging.imageops.tests.bufimgop.filternull=disabled
|
||||
graphics.imaging.imageops.tests.bufimgop.filtercached=disabled
|
||||
graphics.imaging.imageops.tests.rasterop.filternull=disabled
|
||||
graphics.imaging.imageops.tests.rasterop.filtercached=disabled
|
||||
graphics.misc.copytests.copyAreaVert=disabled
|
||||
graphics.misc.copytests.copyAreaHoriz=disabled
|
||||
graphics.misc.copytests.copyAreaDiag=disabled
|
||||
pixel.opts.renderto=Off
|
||||
pixel.opts.renderfrom=Off
|
||||
pixel.src.1BitBinary=disabled
|
||||
pixel.src.2BitBinary=disabled
|
||||
pixel.src.4BitBinary=disabled
|
||||
pixel.src.ByteIndexed=disabled
|
||||
pixel.src.ByteGray=disabled
|
||||
pixel.src.Short555=disabled
|
||||
pixel.src.Short565=disabled
|
||||
pixel.src.ShortGray=disabled
|
||||
pixel.src.3ByteBgr=disabled
|
||||
pixel.src.4ByteAbgr=disabled
|
||||
pixel.src.IntXrgb=disabled
|
||||
pixel.src.IntXbgr=disabled
|
||||
pixel.src.IntArgb=disabled
|
||||
pixel.bimgtests.getrgb=disabled
|
||||
pixel.bimgtests.setrgb=disabled
|
||||
pixel.rastests.getdataelem=disabled
|
||||
pixel.rastests.setdataelem=disabled
|
||||
pixel.rastests.getpixel=disabled
|
||||
pixel.rastests.setpixel=disabled
|
||||
pixel.dbtests.getelem=disabled
|
||||
pixel.dbtests.setelem=disabled
|
||||
text.opts.data.tlength=16
|
||||
text.opts.data.tscript=english
|
||||
text.opts.font.fname=serif,physical
|
||||
text.opts.font.fstyle=0
|
||||
text.opts.font.fsize=13.0
|
||||
text.opts.font.ftx=Identity
|
||||
text.opts.graphics.textaa=Off
|
||||
text.opts.graphics.tfm=Off
|
||||
text.opts.graphics.gaa=Off
|
||||
text.opts.graphics.gtx=Identity
|
||||
text.opts.advopts.gvstyle=0
|
||||
text.opts.advopts.tlruns=1
|
||||
text.opts.advopts.maptype=FONT
|
||||
text.Rendering.tests.drawString=disabled
|
||||
text.Rendering.tests.drawChars=disabled
|
||||
text.Rendering.tests.drawBytes=disabled
|
||||
text.Rendering.tests.drawGlyphVectors=disabled
|
||||
text.Rendering.tests.drawTextLayout=disabled
|
||||
text.Measuring.tests.stringWidth=disabled
|
||||
text.Measuring.tests.stringBounds=disabled
|
||||
text.Measuring.tests.charsWidth=disabled
|
||||
text.Measuring.tests.charsBounds=disabled
|
||||
text.Measuring.tests.fontcandisplay=disabled
|
||||
text.Measuring.tests.gvWidth=disabled
|
||||
text.Measuring.tests.gvLogicalBounds=disabled
|
||||
text.Measuring.tests.gvVisualBounds=disabled
|
||||
text.Measuring.tests.gvPixelBounds=disabled
|
||||
text.Measuring.tests.gvOutline=disabled
|
||||
text.Measuring.tests.gvGlyphLogicalBounds=disabled
|
||||
text.Measuring.tests.gvGlyphVisualBounds=disabled
|
||||
text.Measuring.tests.gvGlyphPixelBounds=disabled
|
||||
text.Measuring.tests.gvGlyphOutline=disabled
|
||||
text.Measuring.tests.gvGlyphTransform=disabled
|
||||
text.Measuring.tests.gvGlyphMetrics=disabled
|
||||
text.Measuring.tests.tlAdvance=disabled
|
||||
text.Measuring.tests.tlAscent=disabled
|
||||
text.Measuring.tests.tlBounds=disabled
|
||||
text.Measuring.tests.tlGetCaretInfo=disabled
|
||||
text.Measuring.tests.tlGetNextHit=disabled
|
||||
text.Measuring.tests.tlGetCaretShape=disabled
|
||||
text.Measuring.tests.tlGetLogicalHighlightShape=disabled
|
||||
text.Measuring.tests.tlHitTest=disabled
|
||||
text.Measuring.tests.tlOutline=disabled
|
||||
text.construction.tests.gvfromfontstring=disabled
|
||||
text.construction.tests.gvfromfontchars=disabled
|
||||
text.construction.tests.gvfromfontci=disabled
|
||||
text.construction.tests.gvfromfontglyphs=disabled
|
||||
text.construction.tests.gvfromfontlayout=disabled
|
||||
text.construction.tests.tlfromfont=disabled
|
||||
text.construction.tests.tlfrommap=disabled
|
||||
imageio.opts.size=250
|
||||
imageio.opts.content=photo
|
||||
imageio.input.opts.general.source.file=disabled
|
||||
imageio.input.opts.general.source.url=disabled
|
||||
imageio.input.opts.general.source.byteArray=disabled
|
||||
imageio.input.opts.imageio.useCache=Off
|
||||
imageio.input.image.toolkit.opts.format=
|
||||
imageio.input.image.toolkit.tests.createImage=disabled
|
||||
imageio.input.image.imageio.opts.format=
|
||||
imageio.input.image.imageio.tests.imageioRead=disabled
|
||||
imageio.input.image.imageio.reader.opts.seekForwardOnly=On
|
||||
imageio.input.image.imageio.reader.opts.ignoreMetadata=On
|
||||
imageio.input.image.imageio.reader.opts.installListener=Off
|
||||
imageio.input.image.imageio.reader.tests.read=disabled
|
||||
imageio.input.image.imageio.reader.tests.getImageMetadata=disabled
|
||||
imageio.input.stream.tests.construct=disabled
|
||||
imageio.input.stream.tests.read=disabled
|
||||
imageio.input.stream.tests.readByteArray=disabled
|
||||
imageio.input.stream.tests.readFullyByteArray=disabled
|
||||
imageio.input.stream.tests.readBit=disabled
|
||||
imageio.input.stream.tests.readByte=disabled
|
||||
imageio.input.stream.tests.readUnsignedByte=disabled
|
||||
imageio.input.stream.tests.readShort=disabled
|
||||
imageio.input.stream.tests.readUnsignedShort=disabled
|
||||
imageio.input.stream.tests.readInt=disabled
|
||||
imageio.input.stream.tests.readUnsignedInt=disabled
|
||||
imageio.input.stream.tests.readFloat=disabled
|
||||
imageio.input.stream.tests.readLong=disabled
|
||||
imageio.input.stream.tests.readDouble=disabled
|
||||
imageio.input.stream.tests.skipBytes=disabled
|
||||
imageio.output.opts.general.dest.file=disabled
|
||||
imageio.output.opts.general.dest.byteArray=disabled
|
||||
imageio.output.opts.imageio.useCache=Off
|
||||
imageio.output.image.imageio.opts.format=
|
||||
imageio.output.image.imageio.tests.imageioWrite=disabled
|
||||
imageio.output.image.imageio.writer.opts.installListener=Off
|
||||
imageio.output.image.imageio.writer.tests.write=disabled
|
||||
imageio.output.stream.tests.construct=disabled
|
||||
imageio.output.stream.tests.write=disabled
|
||||
imageio.output.stream.tests.writeByteArray=disabled
|
||||
imageio.output.stream.tests.writeBit=disabled
|
||||
imageio.output.stream.tests.writeByte=disabled
|
||||
imageio.output.stream.tests.writeShort=disabled
|
||||
imageio.output.stream.tests.writeInt=disabled
|
||||
imageio.output.stream.tests.writeFloat=disabled
|
||||
imageio.output.stream.tests.writeLong=disabled
|
||||
imageio.output.stream.tests.writeDouble=disabled
|
||||
cmm.opts.profiles=1001
|
||||
cmm.colorconv.data.fromRGB=disabled
|
||||
cmm.colorconv.data.toRGB=disabled
|
||||
cmm.colorconv.data.fromCIEXYZ=disabled
|
||||
cmm.colorconv.data.toCIEXYZ=disabled
|
||||
cmm.colorconv.ccop.ccopOptions.size=250
|
||||
cmm.colorconv.ccop.ccopOptions.content=photo
|
||||
cmm.colorconv.ccop.ccopOptions.srcType=INT_RGB
|
||||
cmm.colorconv.ccop.ccopOptions.dstType=INT_RGB
|
||||
cmm.colorconv.ccop.op_img=disabled
|
||||
cmm.colorconv.ccop.op_rst=disabled
|
||||
cmm.colorconv.ccop.op_draw=disabled
|
||||
cmm.colorconv.embed.embedOptions.Images=512x512
|
||||
cmm.colorconv.embed.embd_img_read=disabled
|
||||
cmm.profiles.getHeader=disabled
|
||||
cmm.profiles.getNumComponents=disabled
|
||||
267
jb/project/tools/perf/j2dbopts_poly250-rand_col.txt
Normal file
267
jb/project/tools/perf/j2dbopts_poly250-rand_col.txt
Normal file
@@ -0,0 +1,267 @@
|
||||
prog.verbose=disabled
|
||||
prog.printresults=enabled
|
||||
global.env.outputwidth=640
|
||||
global.env.outputheight=480
|
||||
global.env.runcount=5
|
||||
global.env.repcount=0
|
||||
global.env.testtime=2500
|
||||
global.results.workunits=units
|
||||
global.results.timeunits=sec
|
||||
global.results.ratio=unitspersec
|
||||
global.dest.offscreen=disabled
|
||||
global.dest.frame.defaultframe=enabled
|
||||
global.dest.frame.transframe=disabled
|
||||
global.dest.frame.shapedframe=disabled
|
||||
global.dest.frame.shapedtransframe=disabled
|
||||
global.dest.compatimg.compatimg=disabled
|
||||
global.dest.compatimg.opqcompatimg=disabled
|
||||
global.dest.compatimg.bmcompatimg=disabled
|
||||
global.dest.compatimg.transcompatimg=disabled
|
||||
global.dest.volimg.volimg=disabled
|
||||
global.dest.volimg.opqvolimg=disabled
|
||||
global.dest.volimg.bmvolimg=disabled
|
||||
global.dest.volimg.transvolimg=disabled
|
||||
global.dest.bufimg.IntXrgb=disabled
|
||||
global.dest.bufimg.IntArgb=disabled
|
||||
global.dest.bufimg.IntArgbPre=disabled
|
||||
global.dest.bufimg.3ByteBgr=disabled
|
||||
global.dest.bufimg.ByteIndexed=disabled
|
||||
global.dest.bufimg.ByteGray=disabled
|
||||
global.dest.bufimg.4ByteAbgr=disabled
|
||||
global.dest.bufimg.4ByteAbgrPre=disabled
|
||||
global.dest.bufimg.custom=disabled
|
||||
graphics.opts.anim=2
|
||||
graphics.opts.sizes=250
|
||||
graphics.opts.alpharule=SrcOver
|
||||
graphics.opts.transform=ident
|
||||
graphics.opts.extraalpha=Off
|
||||
graphics.opts.xormode=Off
|
||||
graphics.opts.clip=Off
|
||||
graphics.opts.renderhint=Default
|
||||
graphics.render.opts.paint=random
|
||||
graphics.render.opts.alphacolor=Off
|
||||
graphics.render.opts.antialias=Off
|
||||
graphics.render.opts.stroke=width1
|
||||
graphics.render.tests.drawLine=disabled
|
||||
graphics.render.tests.drawLineHoriz=disabled
|
||||
graphics.render.tests.drawLineVert=disabled
|
||||
graphics.render.tests.fillRect=disabled
|
||||
graphics.render.tests.drawRect=disabled
|
||||
graphics.render.tests.fillOval=disabled
|
||||
graphics.render.tests.drawOval=disabled
|
||||
graphics.render.tests.fillPoly=disabled
|
||||
graphics.render.tests.drawPoly=enabled
|
||||
graphics.render.tests.shape.fillCubic=disabled
|
||||
graphics.render.tests.shape.drawCubic=disabled
|
||||
graphics.render.tests.shape.fillEllipse2D=disabled
|
||||
graphics.render.tests.shape.drawEllipse2D=disabled
|
||||
graphics.imaging.src.offscr.opaque=disabled
|
||||
graphics.imaging.src.offscr.bitmask=disabled
|
||||
graphics.imaging.src.offscr.translucent=disabled
|
||||
graphics.imaging.src.opqcompatimg.opaque=disabled
|
||||
graphics.imaging.src.opqcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.opqcompatimg.translucent=disabled
|
||||
graphics.imaging.src.bmcompatimg.opaque=disabled
|
||||
graphics.imaging.src.bmcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.bmcompatimg.translucent=disabled
|
||||
graphics.imaging.src.transcompatimg.opaque=disabled
|
||||
graphics.imaging.src.transcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.transcompatimg.translucent=disabled
|
||||
graphics.imaging.src.opqvolimg.opaque=disabled
|
||||
graphics.imaging.src.opqvolimg.bitmask=disabled
|
||||
graphics.imaging.src.opqvolimg.translucent=disabled
|
||||
graphics.imaging.src.bmvolimg.opaque=disabled
|
||||
graphics.imaging.src.bmvolimg.bitmask=disabled
|
||||
graphics.imaging.src.bmvolimg.translucent=disabled
|
||||
graphics.imaging.src.transvolimg.opaque=disabled
|
||||
graphics.imaging.src.transvolimg.bitmask=disabled
|
||||
graphics.imaging.src.transvolimg.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.opaque=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.translucent=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.translucent=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.translucent=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.opaque=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.translucent=disabled
|
||||
graphics.imaging.benchmarks.opts.interpolation=Nearest neighbor
|
||||
graphics.imaging.benchmarks.opts.touchsrc=Off
|
||||
graphics.imaging.benchmarks.tests.drawimage=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagebg=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescaleup=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescaledown=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescalesplit=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagetxform=disabled
|
||||
graphics.imaging.imageops.opts.op=convolve3x3zero
|
||||
graphics.imaging.imageops.tests.graphics2d.drawimageop=disabled
|
||||
graphics.imaging.imageops.tests.bufimgop.filternull=disabled
|
||||
graphics.imaging.imageops.tests.bufimgop.filtercached=disabled
|
||||
graphics.imaging.imageops.tests.rasterop.filternull=disabled
|
||||
graphics.imaging.imageops.tests.rasterop.filtercached=disabled
|
||||
graphics.misc.copytests.copyAreaVert=disabled
|
||||
graphics.misc.copytests.copyAreaHoriz=disabled
|
||||
graphics.misc.copytests.copyAreaDiag=disabled
|
||||
pixel.opts.renderto=Off
|
||||
pixel.opts.renderfrom=Off
|
||||
pixel.src.1BitBinary=disabled
|
||||
pixel.src.2BitBinary=disabled
|
||||
pixel.src.4BitBinary=disabled
|
||||
pixel.src.ByteIndexed=disabled
|
||||
pixel.src.ByteGray=disabled
|
||||
pixel.src.Short555=disabled
|
||||
pixel.src.Short565=disabled
|
||||
pixel.src.ShortGray=disabled
|
||||
pixel.src.3ByteBgr=disabled
|
||||
pixel.src.4ByteAbgr=disabled
|
||||
pixel.src.IntXrgb=disabled
|
||||
pixel.src.IntXbgr=disabled
|
||||
pixel.src.IntArgb=disabled
|
||||
pixel.bimgtests.getrgb=disabled
|
||||
pixel.bimgtests.setrgb=disabled
|
||||
pixel.rastests.getdataelem=disabled
|
||||
pixel.rastests.setdataelem=disabled
|
||||
pixel.rastests.getpixel=disabled
|
||||
pixel.rastests.setpixel=disabled
|
||||
pixel.dbtests.getelem=disabled
|
||||
pixel.dbtests.setelem=disabled
|
||||
text.opts.data.tlength=16
|
||||
text.opts.data.tscript=english
|
||||
text.opts.font.fname=serif,physical
|
||||
text.opts.font.fstyle=0
|
||||
text.opts.font.fsize=13.0
|
||||
text.opts.font.ftx=Identity
|
||||
text.opts.graphics.textaa=Off
|
||||
text.opts.graphics.tfm=Off
|
||||
text.opts.graphics.gaa=Off
|
||||
text.opts.graphics.gtx=Identity
|
||||
text.opts.advopts.gvstyle=0
|
||||
text.opts.advopts.tlruns=1
|
||||
text.opts.advopts.maptype=FONT
|
||||
text.Rendering.tests.drawString=disabled
|
||||
text.Rendering.tests.drawChars=disabled
|
||||
text.Rendering.tests.drawBytes=disabled
|
||||
text.Rendering.tests.drawGlyphVectors=disabled
|
||||
text.Rendering.tests.drawTextLayout=disabled
|
||||
text.Measuring.tests.stringWidth=disabled
|
||||
text.Measuring.tests.stringBounds=disabled
|
||||
text.Measuring.tests.charsWidth=disabled
|
||||
text.Measuring.tests.charsBounds=disabled
|
||||
text.Measuring.tests.fontcandisplay=disabled
|
||||
text.Measuring.tests.gvWidth=disabled
|
||||
text.Measuring.tests.gvLogicalBounds=disabled
|
||||
text.Measuring.tests.gvVisualBounds=disabled
|
||||
text.Measuring.tests.gvPixelBounds=disabled
|
||||
text.Measuring.tests.gvOutline=disabled
|
||||
text.Measuring.tests.gvGlyphLogicalBounds=disabled
|
||||
text.Measuring.tests.gvGlyphVisualBounds=disabled
|
||||
text.Measuring.tests.gvGlyphPixelBounds=disabled
|
||||
text.Measuring.tests.gvGlyphOutline=disabled
|
||||
text.Measuring.tests.gvGlyphTransform=disabled
|
||||
text.Measuring.tests.gvGlyphMetrics=disabled
|
||||
text.Measuring.tests.tlAdvance=disabled
|
||||
text.Measuring.tests.tlAscent=disabled
|
||||
text.Measuring.tests.tlBounds=disabled
|
||||
text.Measuring.tests.tlGetCaretInfo=disabled
|
||||
text.Measuring.tests.tlGetNextHit=disabled
|
||||
text.Measuring.tests.tlGetCaretShape=disabled
|
||||
text.Measuring.tests.tlGetLogicalHighlightShape=disabled
|
||||
text.Measuring.tests.tlHitTest=disabled
|
||||
text.Measuring.tests.tlOutline=disabled
|
||||
text.construction.tests.gvfromfontstring=disabled
|
||||
text.construction.tests.gvfromfontchars=disabled
|
||||
text.construction.tests.gvfromfontci=disabled
|
||||
text.construction.tests.gvfromfontglyphs=disabled
|
||||
text.construction.tests.gvfromfontlayout=disabled
|
||||
text.construction.tests.tlfromfont=disabled
|
||||
text.construction.tests.tlfrommap=disabled
|
||||
imageio.opts.size=250
|
||||
imageio.opts.content=photo
|
||||
imageio.input.opts.general.source.file=disabled
|
||||
imageio.input.opts.general.source.url=disabled
|
||||
imageio.input.opts.general.source.byteArray=disabled
|
||||
imageio.input.opts.imageio.useCache=Off
|
||||
imageio.input.image.toolkit.opts.format=
|
||||
imageio.input.image.toolkit.tests.createImage=disabled
|
||||
imageio.input.image.imageio.opts.format=
|
||||
imageio.input.image.imageio.tests.imageioRead=disabled
|
||||
imageio.input.image.imageio.reader.opts.seekForwardOnly=On
|
||||
imageio.input.image.imageio.reader.opts.ignoreMetadata=On
|
||||
imageio.input.image.imageio.reader.opts.installListener=Off
|
||||
imageio.input.image.imageio.reader.tests.read=disabled
|
||||
imageio.input.image.imageio.reader.tests.getImageMetadata=disabled
|
||||
imageio.input.stream.tests.construct=disabled
|
||||
imageio.input.stream.tests.read=disabled
|
||||
imageio.input.stream.tests.readByteArray=disabled
|
||||
imageio.input.stream.tests.readFullyByteArray=disabled
|
||||
imageio.input.stream.tests.readBit=disabled
|
||||
imageio.input.stream.tests.readByte=disabled
|
||||
imageio.input.stream.tests.readUnsignedByte=disabled
|
||||
imageio.input.stream.tests.readShort=disabled
|
||||
imageio.input.stream.tests.readUnsignedShort=disabled
|
||||
imageio.input.stream.tests.readInt=disabled
|
||||
imageio.input.stream.tests.readUnsignedInt=disabled
|
||||
imageio.input.stream.tests.readFloat=disabled
|
||||
imageio.input.stream.tests.readLong=disabled
|
||||
imageio.input.stream.tests.readDouble=disabled
|
||||
imageio.input.stream.tests.skipBytes=disabled
|
||||
imageio.output.opts.general.dest.file=disabled
|
||||
imageio.output.opts.general.dest.byteArray=disabled
|
||||
imageio.output.opts.imageio.useCache=Off
|
||||
imageio.output.image.imageio.opts.format=
|
||||
imageio.output.image.imageio.tests.imageioWrite=disabled
|
||||
imageio.output.image.imageio.writer.opts.installListener=Off
|
||||
imageio.output.image.imageio.writer.tests.write=disabled
|
||||
imageio.output.stream.tests.construct=disabled
|
||||
imageio.output.stream.tests.write=disabled
|
||||
imageio.output.stream.tests.writeByteArray=disabled
|
||||
imageio.output.stream.tests.writeBit=disabled
|
||||
imageio.output.stream.tests.writeByte=disabled
|
||||
imageio.output.stream.tests.writeShort=disabled
|
||||
imageio.output.stream.tests.writeInt=disabled
|
||||
imageio.output.stream.tests.writeFloat=disabled
|
||||
imageio.output.stream.tests.writeLong=disabled
|
||||
imageio.output.stream.tests.writeDouble=disabled
|
||||
cmm.opts.profiles=1001
|
||||
cmm.colorconv.data.fromRGB=disabled
|
||||
cmm.colorconv.data.toRGB=disabled
|
||||
cmm.colorconv.data.fromCIEXYZ=disabled
|
||||
cmm.colorconv.data.toCIEXYZ=disabled
|
||||
cmm.colorconv.ccop.ccopOptions.size=250
|
||||
cmm.colorconv.ccop.ccopOptions.content=photo
|
||||
cmm.colorconv.ccop.ccopOptions.srcType=INT_RGB
|
||||
cmm.colorconv.ccop.ccopOptions.dstType=INT_RGB
|
||||
cmm.colorconv.ccop.op_img=disabled
|
||||
cmm.colorconv.ccop.op_rst=disabled
|
||||
cmm.colorconv.ccop.op_draw=disabled
|
||||
cmm.colorconv.embed.embedOptions.Images=512x512
|
||||
cmm.colorconv.embed.embd_img_read=disabled
|
||||
cmm.profiles.getHeader=disabled
|
||||
cmm.profiles.getNumComponents=disabled
|
||||
267
jb/project/tools/perf/j2dbopts_poly250.txt
Normal file
267
jb/project/tools/perf/j2dbopts_poly250.txt
Normal file
@@ -0,0 +1,267 @@
|
||||
prog.verbose=disabled
|
||||
prog.printresults=enabled
|
||||
global.env.outputwidth=640
|
||||
global.env.outputheight=480
|
||||
global.env.runcount=5
|
||||
global.env.repcount=0
|
||||
global.env.testtime=2500
|
||||
global.results.workunits=units
|
||||
global.results.timeunits=sec
|
||||
global.results.ratio=unitspersec
|
||||
global.dest.offscreen=disabled
|
||||
global.dest.frame.defaultframe=enabled
|
||||
global.dest.frame.transframe=disabled
|
||||
global.dest.frame.shapedframe=disabled
|
||||
global.dest.frame.shapedtransframe=disabled
|
||||
global.dest.compatimg.compatimg=disabled
|
||||
global.dest.compatimg.opqcompatimg=disabled
|
||||
global.dest.compatimg.bmcompatimg=disabled
|
||||
global.dest.compatimg.transcompatimg=disabled
|
||||
global.dest.volimg.volimg=disabled
|
||||
global.dest.volimg.opqvolimg=disabled
|
||||
global.dest.volimg.bmvolimg=disabled
|
||||
global.dest.volimg.transvolimg=disabled
|
||||
global.dest.bufimg.IntXrgb=disabled
|
||||
global.dest.bufimg.IntArgb=disabled
|
||||
global.dest.bufimg.IntArgbPre=disabled
|
||||
global.dest.bufimg.3ByteBgr=disabled
|
||||
global.dest.bufimg.ByteIndexed=disabled
|
||||
global.dest.bufimg.ByteGray=disabled
|
||||
global.dest.bufimg.4ByteAbgr=disabled
|
||||
global.dest.bufimg.4ByteAbgrPre=disabled
|
||||
global.dest.bufimg.custom=disabled
|
||||
graphics.opts.anim=2
|
||||
graphics.opts.sizes=250
|
||||
graphics.opts.alpharule=SrcOver
|
||||
graphics.opts.transform=ident
|
||||
graphics.opts.extraalpha=Off
|
||||
graphics.opts.xormode=Off
|
||||
graphics.opts.clip=Off
|
||||
graphics.opts.renderhint=Default
|
||||
graphics.render.opts.paint=single
|
||||
graphics.render.opts.alphacolor=Off
|
||||
graphics.render.opts.antialias=Off
|
||||
graphics.render.opts.stroke=width1
|
||||
graphics.render.tests.drawLine=disabled
|
||||
graphics.render.tests.drawLineHoriz=disabled
|
||||
graphics.render.tests.drawLineVert=disabled
|
||||
graphics.render.tests.fillRect=disabled
|
||||
graphics.render.tests.drawRect=disabled
|
||||
graphics.render.tests.fillOval=disabled
|
||||
graphics.render.tests.drawOval=disabled
|
||||
graphics.render.tests.fillPoly=disabled
|
||||
graphics.render.tests.drawPoly=enabled
|
||||
graphics.render.tests.shape.fillCubic=disabled
|
||||
graphics.render.tests.shape.drawCubic=disabled
|
||||
graphics.render.tests.shape.fillEllipse2D=disabled
|
||||
graphics.render.tests.shape.drawEllipse2D=disabled
|
||||
graphics.imaging.src.offscr.opaque=disabled
|
||||
graphics.imaging.src.offscr.bitmask=disabled
|
||||
graphics.imaging.src.offscr.translucent=disabled
|
||||
graphics.imaging.src.opqcompatimg.opaque=disabled
|
||||
graphics.imaging.src.opqcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.opqcompatimg.translucent=disabled
|
||||
graphics.imaging.src.bmcompatimg.opaque=disabled
|
||||
graphics.imaging.src.bmcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.bmcompatimg.translucent=disabled
|
||||
graphics.imaging.src.transcompatimg.opaque=disabled
|
||||
graphics.imaging.src.transcompatimg.bitmask=disabled
|
||||
graphics.imaging.src.transcompatimg.translucent=disabled
|
||||
graphics.imaging.src.opqvolimg.opaque=disabled
|
||||
graphics.imaging.src.opqvolimg.bitmask=disabled
|
||||
graphics.imaging.src.opqvolimg.translucent=disabled
|
||||
graphics.imaging.src.bmvolimg.opaque=disabled
|
||||
graphics.imaging.src.bmvolimg.bitmask=disabled
|
||||
graphics.imaging.src.bmvolimg.translucent=disabled
|
||||
graphics.imaging.src.transvolimg.opaque=disabled
|
||||
graphics.imaging.src.transvolimg.bitmask=disabled
|
||||
graphics.imaging.src.transvolimg.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntXrgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntArgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.IntArgbPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.opaque=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.ByteGray.translucent=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.3ByteBgr.translucent=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgr.translucent=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.4ByteAbgrPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.opaque=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.ByteIndexedBm.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntXrgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgb.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanagedIntArgbPre.translucent=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.opaque=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.bitmask=disabled
|
||||
graphics.imaging.src.bufimg.unmanaged3ByteBgr.translucent=disabled
|
||||
graphics.imaging.benchmarks.opts.interpolation=Nearest neighbor
|
||||
graphics.imaging.benchmarks.opts.touchsrc=Off
|
||||
graphics.imaging.benchmarks.tests.drawimage=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagebg=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescaleup=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescaledown=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagescalesplit=disabled
|
||||
graphics.imaging.benchmarks.tests.drawimagetxform=disabled
|
||||
graphics.imaging.imageops.opts.op=convolve3x3zero
|
||||
graphics.imaging.imageops.tests.graphics2d.drawimageop=disabled
|
||||
graphics.imaging.imageops.tests.bufimgop.filternull=disabled
|
||||
graphics.imaging.imageops.tests.bufimgop.filtercached=disabled
|
||||
graphics.imaging.imageops.tests.rasterop.filternull=disabled
|
||||
graphics.imaging.imageops.tests.rasterop.filtercached=disabled
|
||||
graphics.misc.copytests.copyAreaVert=disabled
|
||||
graphics.misc.copytests.copyAreaHoriz=disabled
|
||||
graphics.misc.copytests.copyAreaDiag=disabled
|
||||
pixel.opts.renderto=Off
|
||||
pixel.opts.renderfrom=Off
|
||||
pixel.src.1BitBinary=disabled
|
||||
pixel.src.2BitBinary=disabled
|
||||
pixel.src.4BitBinary=disabled
|
||||
pixel.src.ByteIndexed=disabled
|
||||
pixel.src.ByteGray=disabled
|
||||
pixel.src.Short555=disabled
|
||||
pixel.src.Short565=disabled
|
||||
pixel.src.ShortGray=disabled
|
||||
pixel.src.3ByteBgr=disabled
|
||||
pixel.src.4ByteAbgr=disabled
|
||||
pixel.src.IntXrgb=disabled
|
||||
pixel.src.IntXbgr=disabled
|
||||
pixel.src.IntArgb=disabled
|
||||
pixel.bimgtests.getrgb=disabled
|
||||
pixel.bimgtests.setrgb=disabled
|
||||
pixel.rastests.getdataelem=disabled
|
||||
pixel.rastests.setdataelem=disabled
|
||||
pixel.rastests.getpixel=disabled
|
||||
pixel.rastests.setpixel=disabled
|
||||
pixel.dbtests.getelem=disabled
|
||||
pixel.dbtests.setelem=disabled
|
||||
text.opts.data.tlength=16
|
||||
text.opts.data.tscript=english
|
||||
text.opts.font.fname=serif,physical
|
||||
text.opts.font.fstyle=0
|
||||
text.opts.font.fsize=13.0
|
||||
text.opts.font.ftx=Identity
|
||||
text.opts.graphics.textaa=Off
|
||||
text.opts.graphics.tfm=Off
|
||||
text.opts.graphics.gaa=Off
|
||||
text.opts.graphics.gtx=Identity
|
||||
text.opts.advopts.gvstyle=0
|
||||
text.opts.advopts.tlruns=1
|
||||
text.opts.advopts.maptype=FONT
|
||||
text.Rendering.tests.drawString=disabled
|
||||
text.Rendering.tests.drawChars=disabled
|
||||
text.Rendering.tests.drawBytes=disabled
|
||||
text.Rendering.tests.drawGlyphVectors=disabled
|
||||
text.Rendering.tests.drawTextLayout=disabled
|
||||
text.Measuring.tests.stringWidth=disabled
|
||||
text.Measuring.tests.stringBounds=disabled
|
||||
text.Measuring.tests.charsWidth=disabled
|
||||
text.Measuring.tests.charsBounds=disabled
|
||||
text.Measuring.tests.fontcandisplay=disabled
|
||||
text.Measuring.tests.gvWidth=disabled
|
||||
text.Measuring.tests.gvLogicalBounds=disabled
|
||||
text.Measuring.tests.gvVisualBounds=disabled
|
||||
text.Measuring.tests.gvPixelBounds=disabled
|
||||
text.Measuring.tests.gvOutline=disabled
|
||||
text.Measuring.tests.gvGlyphLogicalBounds=disabled
|
||||
text.Measuring.tests.gvGlyphVisualBounds=disabled
|
||||
text.Measuring.tests.gvGlyphPixelBounds=disabled
|
||||
text.Measuring.tests.gvGlyphOutline=disabled
|
||||
text.Measuring.tests.gvGlyphTransform=disabled
|
||||
text.Measuring.tests.gvGlyphMetrics=disabled
|
||||
text.Measuring.tests.tlAdvance=disabled
|
||||
text.Measuring.tests.tlAscent=disabled
|
||||
text.Measuring.tests.tlBounds=disabled
|
||||
text.Measuring.tests.tlGetCaretInfo=disabled
|
||||
text.Measuring.tests.tlGetNextHit=disabled
|
||||
text.Measuring.tests.tlGetCaretShape=disabled
|
||||
text.Measuring.tests.tlGetLogicalHighlightShape=disabled
|
||||
text.Measuring.tests.tlHitTest=disabled
|
||||
text.Measuring.tests.tlOutline=disabled
|
||||
text.construction.tests.gvfromfontstring=disabled
|
||||
text.construction.tests.gvfromfontchars=disabled
|
||||
text.construction.tests.gvfromfontci=disabled
|
||||
text.construction.tests.gvfromfontglyphs=disabled
|
||||
text.construction.tests.gvfromfontlayout=disabled
|
||||
text.construction.tests.tlfromfont=disabled
|
||||
text.construction.tests.tlfrommap=disabled
|
||||
imageio.opts.size=250
|
||||
imageio.opts.content=photo
|
||||
imageio.input.opts.general.source.file=disabled
|
||||
imageio.input.opts.general.source.url=disabled
|
||||
imageio.input.opts.general.source.byteArray=disabled
|
||||
imageio.input.opts.imageio.useCache=Off
|
||||
imageio.input.image.toolkit.opts.format=
|
||||
imageio.input.image.toolkit.tests.createImage=disabled
|
||||
imageio.input.image.imageio.opts.format=
|
||||
imageio.input.image.imageio.tests.imageioRead=disabled
|
||||
imageio.input.image.imageio.reader.opts.seekForwardOnly=On
|
||||
imageio.input.image.imageio.reader.opts.ignoreMetadata=On
|
||||
imageio.input.image.imageio.reader.opts.installListener=Off
|
||||
imageio.input.image.imageio.reader.tests.read=disabled
|
||||
imageio.input.image.imageio.reader.tests.getImageMetadata=disabled
|
||||
imageio.input.stream.tests.construct=disabled
|
||||
imageio.input.stream.tests.read=disabled
|
||||
imageio.input.stream.tests.readByteArray=disabled
|
||||
imageio.input.stream.tests.readFullyByteArray=disabled
|
||||
imageio.input.stream.tests.readBit=disabled
|
||||
imageio.input.stream.tests.readByte=disabled
|
||||
imageio.input.stream.tests.readUnsignedByte=disabled
|
||||
imageio.input.stream.tests.readShort=disabled
|
||||
imageio.input.stream.tests.readUnsignedShort=disabled
|
||||
imageio.input.stream.tests.readInt=disabled
|
||||
imageio.input.stream.tests.readUnsignedInt=disabled
|
||||
imageio.input.stream.tests.readFloat=disabled
|
||||
imageio.input.stream.tests.readLong=disabled
|
||||
imageio.input.stream.tests.readDouble=disabled
|
||||
imageio.input.stream.tests.skipBytes=disabled
|
||||
imageio.output.opts.general.dest.file=disabled
|
||||
imageio.output.opts.general.dest.byteArray=disabled
|
||||
imageio.output.opts.imageio.useCache=Off
|
||||
imageio.output.image.imageio.opts.format=
|
||||
imageio.output.image.imageio.tests.imageioWrite=disabled
|
||||
imageio.output.image.imageio.writer.opts.installListener=Off
|
||||
imageio.output.image.imageio.writer.tests.write=disabled
|
||||
imageio.output.stream.tests.construct=disabled
|
||||
imageio.output.stream.tests.write=disabled
|
||||
imageio.output.stream.tests.writeByteArray=disabled
|
||||
imageio.output.stream.tests.writeBit=disabled
|
||||
imageio.output.stream.tests.writeByte=disabled
|
||||
imageio.output.stream.tests.writeShort=disabled
|
||||
imageio.output.stream.tests.writeInt=disabled
|
||||
imageio.output.stream.tests.writeFloat=disabled
|
||||
imageio.output.stream.tests.writeLong=disabled
|
||||
imageio.output.stream.tests.writeDouble=disabled
|
||||
cmm.opts.profiles=1001
|
||||
cmm.colorconv.data.fromRGB=disabled
|
||||
cmm.colorconv.data.toRGB=disabled
|
||||
cmm.colorconv.data.fromCIEXYZ=disabled
|
||||
cmm.colorconv.data.toCIEXYZ=disabled
|
||||
cmm.colorconv.ccop.ccopOptions.size=250
|
||||
cmm.colorconv.ccop.ccopOptions.content=photo
|
||||
cmm.colorconv.ccop.ccopOptions.srcType=INT_RGB
|
||||
cmm.colorconv.ccop.ccopOptions.dstType=INT_RGB
|
||||
cmm.colorconv.ccop.op_img=disabled
|
||||
cmm.colorconv.ccop.op_rst=disabled
|
||||
cmm.colorconv.ccop.op_draw=disabled
|
||||
cmm.colorconv.embed.embedOptions.Images=512x512
|
||||
cmm.colorconv.embed.embd_img_read=disabled
|
||||
cmm.profiles.getHeader=disabled
|
||||
cmm.profiles.getNumComponents=disabled
|
||||
137
jb/project/tools/perf/run_inc.sh
Normal file
137
jb/project/tools/perf/run_inc.sh
Normal file
@@ -0,0 +1,137 @@
|
||||
export LC_ALL=C
|
||||
ST=1 # sleep between iterations
|
||||
|
||||
# number of iterations (jvm spawned)
|
||||
N=5
|
||||
# number of repeats (within jvm)
|
||||
R=3
|
||||
|
||||
type datamash 2>&1 > /dev/null ; ec=$?
|
||||
if [ $ec -ne 0 ] ; then
|
||||
echo "Missing datamash utility"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DATAMASH_CMD="datamash --format=%.2f -H count x min x q1 x median x q3 x max x mad x"
|
||||
|
||||
J2D_OPTS=""
|
||||
OS=""
|
||||
case "$OSTYPE" in
|
||||
linux*) echo "Linux"
|
||||
;;
|
||||
darwin*) echo "OSX"
|
||||
;;
|
||||
*) echo "unknown: $OSTYPE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
read -r -d '' RENDER_OPS_DOC << EOM
|
||||
rendering_options:
|
||||
-opengl # OpenGL pipeline (windows, linux, macOS)
|
||||
-metal # Metal pipeline (macOS)
|
||||
-vulkan # Vulkan pipeline (WLToolkit)
|
||||
-accelsd # Vulkan full acceleration (WLToolkit, Vulkan)
|
||||
-devnum num # Provide Vulkan device for rendering
|
||||
-tk tk_name # AWT toolkit (linux: WLToolkit|XToolkit)
|
||||
-scale # UI scale
|
||||
-N num # Number of iterations (JVM runs)
|
||||
-R num # Number of repeats in the test
|
||||
EOM
|
||||
|
||||
while [ $# -ge 1 ] ; do
|
||||
case "$1" in
|
||||
-opengl) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.opengl=true"
|
||||
shift
|
||||
;;
|
||||
-metal) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.metal=true"
|
||||
shift
|
||||
;;
|
||||
-vulkan) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.vulkan=true"
|
||||
shift
|
||||
;;
|
||||
-accelsd) J2D_OPTS=$J2D_OPTS" -Dsun.java2d.vulkan.accelsd=true"
|
||||
shift
|
||||
;;
|
||||
-devnum) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
J2D_OPTS=$J2D_OPTS" -Dsun.java2d.vulkan.deviceNumber="$1
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -devnum option. Use: -devnum num"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-tk) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
J2D_OPTS=$J2D_OPTS" -Dawt.toolkit.name="$1
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -tk option. Use: -tk tkname"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-N) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
N=$1
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -N option. Use: -N <number>"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-R) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
R=$1
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -R option. Use: -R <number>"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-scale) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
J2D_OPTS=$J2D_OPTS" -Dsun.java2d.uiScale="$1
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -scale option. Use: -scale scale"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-dSync) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
J2D_OPTS=$J2D_OPTS" -Dsun.java2d.metal.displaySync="$1
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -dSync option. Use: -dSync [true|false]"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-jdk) shift
|
||||
if [ $# -ge 1 ] ; then
|
||||
JAVA=$1/bin/java
|
||||
shift
|
||||
else
|
||||
echo "Invalid parameters for -jdk option"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*) break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ -z "$JAVA" ] ; then
|
||||
BUILD_DIR=`find $BASE_DIR/../../../../build -name '*-release' -type d | head -n 1`
|
||||
JAVA=`find $BUILD_DIR/images/jdk -name java -type f | head -n 1`
|
||||
fi
|
||||
|
||||
JAVA_HOME=`dirname $JAVA`/../
|
||||
"$JAVA" -version
|
||||
|
||||
LANG=C
|
||||
|
||||
WS_ROOT=$BASE_DIR/../../../..
|
||||
|
||||
echo "N: $N"
|
||||
echo "R: $R"
|
||||
echo "J2D_OPTS: $J2D_OPTS"
|
||||
53
jb/project/tools/perf/run_j2b.sh
Executable file
53
jb/project/tools/perf/run_j2b.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASE_DIR=$(dirname "$0")
|
||||
source $BASE_DIR/run_inc.sh
|
||||
|
||||
J2DBENCH_DIR=$WS_ROOT/src/demo/share/java2d/J2DBench
|
||||
|
||||
if [ -z "$J2DBENCH" ]; then
|
||||
if [ ! -f "$J2DBENCH_DIR/dist/J2DBench.jar" ]; then
|
||||
PATH=$JAVA_HOME/bin:$PATH make -C $J2DBENCH_DIR
|
||||
fi
|
||||
if [ ! -f "$J2DBENCH_DIR/dist/J2DBench.jar" ]; then
|
||||
echo "Cannot build J2DBench. You may use J2DBench env variable instead pointing to the J2DBench.jar."
|
||||
exit 1
|
||||
fi
|
||||
J2DBENCH=$J2DBENCH_DIR/dist/J2DBench.jar
|
||||
fi
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
echo "Usage: run_j2b.sh [rendering_options] bench_name"
|
||||
echo
|
||||
echo "bench_name: poly250 poly250-rand_col poly250-AA-rand_col"
|
||||
echo ""
|
||||
echo "$RENDER_OPS_DOC"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ ! -f "$BASE_DIR/j2dbopts_$1.txt" ]; then
|
||||
echo "Unknown test: $1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
OPTS="j2dbopts_$1.txt"
|
||||
#OPTS=j2dbopts_poly250.txt
|
||||
#OPTS=j2dbopts_poly250-rand_col.txt
|
||||
#OPTS=j2dbopts_poly250-AA-rand_col.txt
|
||||
|
||||
echo "OPTS: $OPTS"
|
||||
|
||||
for i in `seq $N`; do
|
||||
if [ $i -eq 1 ]; then
|
||||
echo x
|
||||
fi
|
||||
echo `$JAVA $J2D_OPTS -jar $J2DBENCH \
|
||||
-batch -loadopts $BASE_DIR/$OPTS -saveres pl.res \
|
||||
-title pl -desc pl | awk '/averaged/{print $3}' | head -n1`
|
||||
|
||||
if [ $i -ne $N ]; then
|
||||
sleep $ST
|
||||
fi
|
||||
done | $DATAMASH_CMD | expand -t12
|
||||
88
jb/project/tools/perf/run_rp.sh
Executable file
88
jb/project/tools/perf/run_rp.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
|
||||
#set -euo pipefail
|
||||
#set -x
|
||||
|
||||
BASE_DIR=$(dirname "$0")
|
||||
source $BASE_DIR/run_inc.sh
|
||||
|
||||
RENDERPERFTEST_DIR=$WS_ROOT/test/jdk/performance/client/RenderPerfTest
|
||||
RENDERPERFTEST=""
|
||||
if [ -z "$RENDERPERFTEST" ]; then
|
||||
if [ ! -f "$RENDERPERFTEST_DIR/dist/RenderPerfTest.jar" ]; then
|
||||
PATH=$JAVA_HOME/bin:$PATH make -C $RENDERPERFTEST_DIR
|
||||
fi
|
||||
if [ ! -f "$RENDERPERFTEST_DIR/dist/RenderPerfTest.jar" ]; then
|
||||
echo "Cannot build RenderPerfTest. You may use RENDERPERFTEST env variable instead pointing to the RenderPerfTest.jar."
|
||||
exit 1
|
||||
fi
|
||||
RENDERPERFTEST=$RENDERPERFTEST_DIR/dist/RenderPerfTest.jar
|
||||
fi
|
||||
|
||||
TRACE=false
|
||||
|
||||
# removes leading hyphen
|
||||
mode_param="${1/-}"
|
||||
MODE="Robot"
|
||||
while [ $# -ge 1 ] ; do
|
||||
case "$1" in
|
||||
-onscreen) MODE="Robot"
|
||||
shift
|
||||
;;
|
||||
-volatile) MODE="Volatile"
|
||||
shift
|
||||
;;
|
||||
-buffer) MODE="Buffer"
|
||||
shift
|
||||
;;
|
||||
*) break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ($# -eq 1 && "$1" == "-help") || ($# -eq 0) ]] ; then
|
||||
echo "Usage: run_rp.sh [rp_rendering_mode] [rendering_options] bench_name"
|
||||
echo
|
||||
echo "bench_name: ArgbSurfaceBlitImage ArgbSwBlitImage BgrSurfaceBlitImage BgrSwBlitImage"
|
||||
echo " Image ImageAA Image_XOR VolImage VolImageAA"
|
||||
echo " ClipFlatBox ClipFlatBoxAA ClipFlatOval ClipFlatOvalAA"
|
||||
echo " FlatBox FlatBoxAA FlatOval FlatOvalAA FlatOval_XOR FlatQuad FlatQuadAA"
|
||||
echo " RotatedBox RotatedBoxAA RotatedBox_XOR RotatedOval RotatedOvalAA"
|
||||
echo " WiredBox WiredBoxAA WiredBubbles WiredBubblesAA WiredQuad WiredQuadAA"
|
||||
echo " Lines LinesAA Lines_XOR"
|
||||
echo " TextGray TextLCD TextLCD_XOR TextNoAA TextNoAA_XOR"
|
||||
echo " LargeTextGray LargeTextLCD LargeTextNoAA WhiteTextGray WhiteTextLCD WhiteTextNoAA"
|
||||
echo " LinGrad3RotatedOval LinGrad3RotatedOvalAA LinGradRotatedOval LinGradRotatedOvalAA"
|
||||
echo " RadGrad3RotatedOval RadGrad3RotatedOvalAA"
|
||||
echo ""
|
||||
echo "rp_rendering_mode: "
|
||||
echo " -onscreen : rendering to the window and check it using Robot"
|
||||
echo " -volatile : rendering to volatile image (default)"
|
||||
echo " -buffer : rendering to buffered image"
|
||||
echo "$RENDER_OPS_DOC"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
OPTS=""
|
||||
# use time + repeat
|
||||
OPTS="$OPTS -t -n=$N -e$MODE $1"
|
||||
|
||||
echo "OPTS: $OPTS"
|
||||
|
||||
echo "Unit: Milliseconds (not FPS), lower is better"
|
||||
for i in `seq $R` ; do
|
||||
if [ $i -eq 1 ]; then
|
||||
echo x
|
||||
fi
|
||||
|
||||
# echo "[debug] " + "test run"
|
||||
# $JAVA $J2D_OPTS -DTRACE=$TRACE \
|
||||
# -jar $RENDERPERFTEST $OPTS 2>&1 | awk '/'$1'/{print $3 }' | tee test_run.log
|
||||
|
||||
$JAVA $J2D_OPTS -DTRACE=$TRACE \
|
||||
-jar $RENDERPERFTEST $OPTS -v 2>&1 | tee render_$1_${mode_param}_$i.log | grep -v "^#" | tail -n 1 | \
|
||||
awk '{print $3 }'
|
||||
if [ $i -ne $N ]; then
|
||||
sleep $ST
|
||||
fi
|
||||
done | $DATAMASH_CMD | expand -t12 | tee render_$1_${mode_param}.log
|
||||
39
jb/project/tools/perf/run_sm.sh
Executable file
39
jb/project/tools/perf/run_sm.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASE_DIR=$(dirname "$0")
|
||||
source $BASE_DIR/run_inc.sh
|
||||
|
||||
SWINGMARK_DIR=$WS_ROOT/test/jdk/performance/client/SwingMark
|
||||
|
||||
if [ -z "$SWINGMARK" ]; then
|
||||
if [ ! -f "$SWINGMARK_DIR/dist/SwingMark.jar" ]; then
|
||||
PATH=$JAVA_HOME/bin:$PATH make -C $SWINGMARK_DIR
|
||||
fi
|
||||
if [ ! -f "$SWINGMARK_DIR/dist/SwingMark.jar" ]; then
|
||||
echo "Cannot build SwingMark. You may use SWINGMARK env variable instead pointing to the SwingMark.jar."
|
||||
exit 1
|
||||
fi
|
||||
SWINGMARK=$SWINGMARK_DIR/dist/SwingMark.jar
|
||||
fi
|
||||
|
||||
if [ $# -eq 1 -a "$1" == "--help" ] ; then
|
||||
shift
|
||||
echo "Usage: run_sm [rendering_options]"
|
||||
echo ""
|
||||
echo "$RENDER_OPS_DOC"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for i in `seq $N` ; do
|
||||
if [ $i -eq 1 ]; then
|
||||
echo x
|
||||
fi
|
||||
|
||||
# SwingMark gives 1 global 'Score: <value>'
|
||||
echo `$JAVA $J2D_OPTS -jar $BASE_DIR/../../../../test/jdk/performance/client/SwingMark/dist/SwingMark.jar \
|
||||
-r $R -q -lf javax.swing.plaf.metal.MetalLookAndFeel | awk '/Score/{print $2}'`
|
||||
|
||||
if [ $i -ne $N ]; then
|
||||
sleep $ST
|
||||
fi
|
||||
done | $DATAMASH_CMD | expand -t12
|
||||
@@ -68,7 +68,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \
|
||||
-Duser.language=en -Duser.country=US \
|
||||
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
build.tools.classlist.HelloClasslist $(LOG_DEBUG)
|
||||
build.tools.classlist.HelloClasslist jdk/src/classes/build/tools/classlist/clear.classlist $(LOG_DEBUG)
|
||||
$(GREP) -v HelloClasslist $@.raw > $@.interim
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -Xshare:dump \
|
||||
-XX:SharedClassListFile=$@.interim -XX:SharedArchiveFile=$@.jsa \
|
||||
@@ -79,7 +79,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST
|
||||
-Duser.language=en -Duser.country=US \
|
||||
--module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
build.tools.classlist.HelloClasslist \
|
||||
build.tools.classlist.HelloClasslist jdk/src/classes/build/tools/classlist/clear.classlist \
|
||||
2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \
|
||||
|| ( \
|
||||
exitcode=$$? ; \
|
||||
|
||||
114
make/autoconf/lib-vulkan.m4
Normal file
114
make/autoconf/lib-vulkan.m4
Normal file
@@ -0,0 +1,114 @@
|
||||
#
|
||||
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2025, JetBrains s.r.o.. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# Setup vulkan
|
||||
################################################################################
|
||||
AC_DEFUN_ONCE([LIB_SETUP_VULKAN],
|
||||
[
|
||||
AC_ARG_WITH(vulkan, [AS_HELP_STRING([--with-vulkan],
|
||||
[specify whether we use vulkan])])
|
||||
AC_ARG_WITH(vulkan-include, [AS_HELP_STRING([--with-vulkan-include],
|
||||
[specify directory for the vulkan include files ({with-vulkan-include}/vulkan/vulkan.h)])])
|
||||
AC_ARG_WITH(vulkan-shader-compiler, [AS_HELP_STRING([--with-vulkan-shader-compiler],
|
||||
[specify which shader compiler to use: glslc/glslangValidator])])
|
||||
|
||||
VULKAN_ENABLED=false
|
||||
VULKAN_FLAGS=
|
||||
|
||||
# Find Vulkan SDK
|
||||
if test "x$NEEDS_LIB_VULKAN" = xtrue || test "x${with_vulkan}" = xyes || test "x${with_vulkan_include}" != x ; then
|
||||
|
||||
# Check custom directory
|
||||
if test "x${with_vulkan_include}" != x; then
|
||||
AC_MSG_CHECKING([for ${with_vulkan_include}/vulkan/vulkan.h])
|
||||
if test -s "${with_vulkan_include}/vulkan/vulkan.h"; then
|
||||
VULKAN_ENABLED=true
|
||||
VULKAN_FLAGS="-I${with_vulkan_include}"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Can't find 'vulkan/vulkan.h' under '${with_vulkan_include}'])
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check $VULKAN_SDK
|
||||
if test "x$VULKAN_ENABLED" = xfalse && test "x${VULKAN_SDK}" != x; then
|
||||
AC_MSG_CHECKING([for ${VULKAN_SDK}/include/vulkan/vulkan.h])
|
||||
if test -s "${VULKAN_SDK}/include/vulkan/vulkan.h"; then
|
||||
VULKAN_ENABLED=true
|
||||
VULKAN_FLAGS="-I${VULKAN_SDK}/include"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check default /usr/include location
|
||||
if test "x$VULKAN_ENABLED" = xfalse; then
|
||||
AC_CHECK_HEADERS([vulkan/vulkan.h],
|
||||
[ VULKAN_ENABLED=true ], [ break ]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$VULKAN_ENABLED" = xfalse; then
|
||||
# Vulkan SDK not found
|
||||
HELP_MSG_MISSING_DEPENDENCY([vulkan])
|
||||
AC_MSG_ERROR([Could not find vulkan! $HELP_MSG ])
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find shader compiler - glslc or glslangValidator
|
||||
if test "x$VULKAN_ENABLED" = xtrue; then
|
||||
SHADER_COMPILER=
|
||||
|
||||
# Check glslc
|
||||
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslc); then
|
||||
UTIL_LOOKUP_PROGS(GLSLC, glslc)
|
||||
SHADER_COMPILER="$GLSLC"
|
||||
VULKAN_SHADER_COMPILER="glslc --target-env=vulkan1.2 -mfmt=num -o"
|
||||
fi
|
||||
|
||||
# Check glslangValidator
|
||||
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslangValidator) && \
|
||||
test "x$SHADER_COMPILER" = x; then
|
||||
UTIL_LOOKUP_PROGS(GLSLANG, glslangValidator)
|
||||
SHADER_COMPILER="$GLSLANG"
|
||||
VULKAN_SHADER_COMPILER="glslangValidator --target-env vulkan1.2 -x -o"
|
||||
fi
|
||||
|
||||
if test "x$SHADER_COMPILER" = x; then
|
||||
# Compiler not found
|
||||
VULKAN_ENABLED=false
|
||||
VULKAN_FLAGS=
|
||||
AC_MSG_ERROR([Can't find vulkan shader compiler])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(VULKAN_ENABLED)
|
||||
AC_SUBST(VULKAN_FLAGS)
|
||||
AC_SUBST(VULKAN_SHADER_COMPILER)
|
||||
])
|
||||
@@ -45,8 +45,6 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
fi
|
||||
WAYLAND_CFLAGS=
|
||||
WAYLAND_LIBS=
|
||||
VULKAN_FLAGS=
|
||||
VULKAN_ENABLED=false
|
||||
else
|
||||
WAYLAND_FOUND=no
|
||||
|
||||
@@ -79,7 +77,7 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
if test "x${with_wayland_lib}" != x; then
|
||||
WAYLAND_LIBS="-L${with_wayland_lib} -lwayland-client -lwayland-cursor"
|
||||
fi
|
||||
|
||||
|
||||
if test "x$WAYLAND_FOUND" = xno; then
|
||||
# Are the wayland headers installed in the default /usr/include location?
|
||||
AC_CHECK_HEADERS([wayland-client.h wayland-cursor.h],
|
||||
@@ -97,98 +95,7 @@ AC_DEFUN_ONCE([LIB_SETUP_WAYLAND],
|
||||
AC_MSG_ERROR([Could not find wayland! $HELP_MSG ])
|
||||
fi
|
||||
|
||||
|
||||
# Checking for vulkan sdk
|
||||
|
||||
AC_ARG_WITH(vulkan, [AS_HELP_STRING([--with-vulkan],
|
||||
[specify whether we use vulkan])])
|
||||
|
||||
AC_ARG_WITH(vulkan-include, [AS_HELP_STRING([--with-vulkan-include],
|
||||
[specify directory for the vulkan include files ({with-vulkan-include}/vulkan/vulkan.h)])])
|
||||
|
||||
AC_ARG_WITH(vulkan-shader-compiler, [AS_HELP_STRING([--with-vulkan-shader-compiler],
|
||||
[specify which shader compiler to use: glslc/glslangValidator])])
|
||||
|
||||
if test "x$SUPPORTS_LIB_VULKAN" = xfalse; then
|
||||
|
||||
if (test "x${with_vulkan}" != x && test "x${with_vulkan}" != xno) || \
|
||||
(test "x${with_vulkan_include}" != x && test "x${with_vulkan_include}" != xno); then
|
||||
AC_MSG_WARN([[vulkan not used, so --with-vulkan-include is ignored]])
|
||||
fi
|
||||
VULKAN_FLAGS=
|
||||
VULKAN_ENABLED=false
|
||||
else
|
||||
# Do not build vulkan rendering pipeline by default
|
||||
if (test "x${with_vulkan}" = x && test "x${with_vulkan_include}" = x) || \
|
||||
test "x${with_vulkan}" = xno || test "x${with_vulkan_include}" = xno ; then
|
||||
VULKAN_FLAGS=
|
||||
VULKAN_ENABLED=false
|
||||
else
|
||||
VULKAN_FOUND=no
|
||||
|
||||
if test "x${with_vulkan_include}" != x; then
|
||||
AC_MSG_CHECKING([for ${with_vulkan_include}/vulkan/vulkan.h])
|
||||
if test -s "${with_vulkan_include}/vulkan/vulkan.h"; then
|
||||
VULKAN_FOUND=yes
|
||||
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -I${with_vulkan_include} -DVULKAN_ENABLED"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Can't find 'vulkan/vulkan.h' under '${with_vulkan_include}'])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$VULKAN_FOUND" = xno && test "x${VULKAN_SDK}" != x; then
|
||||
AC_MSG_CHECKING([for ${VULKAN_SDK}/include/vulkan/vulkan.h])
|
||||
if test -s "${VULKAN_SDK}/include/vulkan/vulkan.h"; then
|
||||
VULKAN_FOUND=yes
|
||||
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -I${VULKAN_SDK}/include -DVULKAN_ENABLED"
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$VULKAN_FOUND" = xno; then
|
||||
# Check default /usr/include location
|
||||
AC_CHECK_HEADERS([vulkan/vulkan.h],
|
||||
[ VULKAN_FOUND=yes
|
||||
VULKAN_FLAGS="-DVK_USE_PLATFORM_WAYLAND_KHR -DVULKAN_ENABLED"
|
||||
],
|
||||
[ VULKAN_FOUND=no; break ]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$VULKAN_FOUND" = xno; then
|
||||
HELP_MSG_MISSING_DEPENDENCY([vulkan])
|
||||
AC_MSG_ERROR([Could not find vulkan! $HELP_MSG ])
|
||||
else
|
||||
# Find shader compiler - glslc or glslangValidator
|
||||
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslc); then
|
||||
UTIL_LOOKUP_PROGS(GLSLC, glslc)
|
||||
SHADER_COMPILER="$GLSLC"
|
||||
VULKAN_SHADER_COMPILER="glslc --target-env=vulkan1.2 -mfmt=num -o"
|
||||
fi
|
||||
|
||||
if (test "x${with_vulkan_shader_compiler}" = x || test "x${with_vulkan_shader_compiler}" = xglslangValidator) && \
|
||||
test "x$SHADER_COMPILER" = x; then
|
||||
UTIL_LOOKUP_PROGS(GLSLANG, glslangValidator)
|
||||
SHADER_COMPILER="$GLSLANG"
|
||||
VULKAN_SHADER_COMPILER="glslangValidator --target-env vulkan1.2 -x -o"
|
||||
fi
|
||||
|
||||
if test "x$SHADER_COMPILER" != x; then
|
||||
VULKAN_ENABLED=true
|
||||
else
|
||||
AC_MSG_ERROR([Can't find shader compiler])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(VULKAN_FLAGS)
|
||||
AC_SUBST(VULKAN_SHADER_COMPILER)
|
||||
AC_SUBST(VULKAN_ENABLED)
|
||||
AC_SUBST(WAYLAND_CFLAGS)
|
||||
AC_SUBST(WAYLAND_LIBS)
|
||||
])
|
||||
|
||||
@@ -35,8 +35,9 @@ m4_include([lib-std.m4])
|
||||
m4_include([lib-x11.m4])
|
||||
m4_include([lib-speechd.m4])
|
||||
m4_include([lib-nvdacontrollerclient.m4])
|
||||
m4_include([lib-wayland.m4])
|
||||
m4_include([lib-dbus.m4])
|
||||
m4_include([lib-vulkan.m4])
|
||||
m4_include([lib-wayland.m4])
|
||||
m4_include([lib-tests.m4])
|
||||
|
||||
################################################################################
|
||||
@@ -50,23 +51,23 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
|
||||
NEEDS_LIB_X11=false
|
||||
NEEDS_LIB_SPEECHD=false
|
||||
NEEDS_LIB_WAYLAND=false
|
||||
SUPPORTS_LIB_VULKAN=false
|
||||
elif test "x$ENABLE_HEADLESS_ONLY" = xtrue; then
|
||||
# All other instances need X11, even if building headless only, libawt still
|
||||
# needs X11 headers.
|
||||
NEEDS_LIB_X11=true
|
||||
NEEDS_LIB_SPEECHD=false
|
||||
NEEDS_LIB_WAYLAND=false
|
||||
SUPPORTS_LIB_VULKAN=false
|
||||
else
|
||||
# All other instances need X11 and wayland, even if building headless only, libawt still
|
||||
# needs X11 headers.
|
||||
NEEDS_LIB_X11=true
|
||||
NEEDS_LIB_SPEECHD=true
|
||||
NEEDS_LIB_WAYLAND=true
|
||||
SUPPORTS_LIB_VULKAN=true
|
||||
fi
|
||||
|
||||
# Vulkan is not built by default
|
||||
NEEDS_LIB_VULKAN=false
|
||||
|
||||
# Check if fontconfig is needed
|
||||
if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then
|
||||
# No fontconfig support on windows or macosx
|
||||
@@ -153,6 +154,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
|
||||
LIB_SETUP_X11
|
||||
LIB_SETUP_SPEECHD
|
||||
LIB_SETUP_NVDACONTROLLERCLIENT
|
||||
LIB_SETUP_VULKAN
|
||||
LIB_SETUP_WAYLAND
|
||||
LIB_SETUP_DBUS
|
||||
LIB_TESTS_SETUP_GTEST
|
||||
@@ -193,7 +195,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
|
||||
if test "x$OPENJDK_TARGET_OS" = xwindows; then
|
||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \
|
||||
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib powrprof.lib uuid.lib \
|
||||
ws2_32.lib winmm.lib version.lib psapi.lib"
|
||||
ws2_32.lib winmm.lib version.lib psapi.lib Synchronization.lib"
|
||||
fi
|
||||
LIB_SETUP_JVM_LIBS(BUILD)
|
||||
LIB_SETUP_JVM_LIBS(TARGET)
|
||||
|
||||
@@ -487,9 +487,9 @@ A11Y_JAWS_ANNOUNCING_ENABLED:=@A11Y_JAWS_ANNOUNCING_ENABLED@
|
||||
|
||||
WAYLAND_CFLAGS:=@WAYLAND_CFLAGS@
|
||||
WAYLAND_LIBS:=@WAYLAND_LIBS@
|
||||
VULKAN_ENABLED:=@VULKAN_ENABLED@
|
||||
VULKAN_FLAGS:=@VULKAN_FLAGS@
|
||||
VULKAN_SHADER_COMPILER:=@VULKAN_SHADER_COMPILER@
|
||||
VULKAN_ENABLED:=@VULKAN_ENABLED@
|
||||
|
||||
# The lowest required version of macosx
|
||||
MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -153,6 +155,20 @@ public class HelloClasslist {
|
||||
// an inconsistency in the classlist between builds (see JDK-8295951).
|
||||
// To avoid the problem, load the class explicitly.
|
||||
Class<?> striped64Class = Class.forName("java.util.concurrent.atomic.Striped64$Cell");
|
||||
Files.lines(Path.of(args[0])).forEach(line -> {
|
||||
if (line.isEmpty() || line.charAt(0) == '#') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int index = line.indexOf(' ');
|
||||
if (index <= 0) {
|
||||
return;
|
||||
}
|
||||
String className = line.substring(0, index).replace('/', '.');
|
||||
Class.forName(className);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public HelloClasslist() {}
|
||||
|
||||
6756
make/jdk/src/classes/build/tools/classlist/clear.classlist
Normal file
6756
make/jdk/src/classes/build/tools/classlist/clear.classlist
Normal file
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,6 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
sun/awt/wl \
|
||||
sun/java2d/wl \
|
||||
sun/java2d/x11 \
|
||||
sun/java2d/vulkan \
|
||||
sun/java2d/jules \
|
||||
sun/java2d/xr \
|
||||
com/sun/java/swing/plaf/gtk \
|
||||
@@ -139,6 +138,13 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
EXCLUDE_FILES += sun/awt/AWTCharset.java
|
||||
endif
|
||||
|
||||
ifneq ($(VULKAN_ENABLED), true)
|
||||
# WLToolkit needs Vulkan java classes for initialization
|
||||
ifneq ($(call isTargetOs, linux), true)
|
||||
EXCLUDES += sun/java2d/vulkan
|
||||
endif
|
||||
endif
|
||||
|
||||
# These files do not appear in the build result of the old build. This
|
||||
# is because they are generated sources, but the AUTO_JAVA_FILES won't
|
||||
# pick them up since they aren't generated when the source dirs are
|
||||
|
||||
@@ -164,10 +164,23 @@ ifeq ($(call isTargetOs, windows), true)
|
||||
LIBAWT_CFLAGS += $(A11Y_JAWS_ANNOUNCING_CFLAGS)
|
||||
endif
|
||||
|
||||
# Setup Vulkan
|
||||
ifeq ($(VULKAN_ENABLED), true)
|
||||
LIBAWT_EXTRA_SRC += common/font common/java2d/vulkan
|
||||
LIBAWT_EXTRA_HEADER_DIRS += common/font common/java2d/vulkan common/java2d
|
||||
LIBAWT_CFLAGS += $(VULKAN_FLAGS)
|
||||
LIBAWT_EXTRA_FILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/AccelTexturePool.c
|
||||
LIBAWT_EXFILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan/VKStubs.c
|
||||
VULKAN_EXCLUDES := vulkan
|
||||
else
|
||||
LIBAWT_EXTRA_FILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan/VKStubs.c
|
||||
VULKAN_EXCLUDES := vulkan java2d/vulkan
|
||||
endif
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
|
||||
NAME := awt, \
|
||||
EXTRA_SRC := $(LIBAWT_EXTRA_SRC), \
|
||||
EXCLUDES := $(LIBAWT_EXCLUDES), \
|
||||
EXTRA_FILES := $(LIBAWT_EXTRA_FILES), \
|
||||
EXCLUDE_FILES := $(LIBAWT_EXFILES), \
|
||||
OPTIMIZATION := HIGHEST, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS) $(DBUS_CFLAGS), \
|
||||
@@ -237,7 +250,7 @@ spirv-name = $(strip $1).h
|
||||
ifeq ($(VULKAN_ENABLED), true)
|
||||
$(eval $(call SetupCopyFiles, COMPILE_VULKAN_SHADERS, \
|
||||
SRC := $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan, \
|
||||
FILES := $(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan), \
|
||||
FILES := $(filter-out %.glsl, $(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan)), \
|
||||
DEST := $(SUPPORT_OUTPUTDIR)/headers/java.desktop/vulkan/spirv, \
|
||||
MACRO := compile-spirv, \
|
||||
NAME_MACRO := spirv-name, \
|
||||
@@ -245,14 +258,14 @@ ifeq ($(VULKAN_ENABLED), true)
|
||||
VULKAN_SHADER_LIST = $(SUPPORT_OUTPUTDIR)/headers/java.desktop/vulkan/shader_list.h
|
||||
$(VULKAN_SHADER_LIST): $(COMPILE_VULKAN_SHADERS)
|
||||
> $(VULKAN_SHADER_LIST) $(NEWLINE) \
|
||||
$(foreach f, $(patsubst $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan/%,%,$(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan)), \
|
||||
$(foreach f, $(patsubst $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan/%,%,$(filter-out %.glsl, $(call FindFiles, $(TOPDIR)/src/$(MODULE)/share/glsl/vulkan))), \
|
||||
$(ECHO) SHADER_ENTRY\($(subst .,$(COMMA),$(subst /,_,$f))\) >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
|
||||
$(ECHO) '#ifdef INCLUDE_BYTECODE' >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
|
||||
$(ECHO) '#include "spirv/$f.h"' >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
|
||||
$(ECHO) BYTECODE_END >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
|
||||
$(ECHO) '#endif' >> $(VULKAN_SHADER_LIST) $(NEWLINE) \
|
||||
)
|
||||
$(BUILD_LIBAWT): $(VULKAN_SHADER_LIST)
|
||||
$(BUILD_LIBAWT_TARGET_DEPS): $(VULKAN_SHADER_LIST)
|
||||
endif
|
||||
|
||||
TARGETS += $(BUILD_LIBAWT)
|
||||
@@ -382,18 +395,13 @@ ifeq ($(call isTargetOs, windows macosx), false)
|
||||
common/wayland \
|
||||
#
|
||||
|
||||
LIBAWT_WLAWT_EXCLUDES := medialib debug opengl x11
|
||||
LIBAWT_WLAWT_EXCLUDES := medialib debug opengl x11 $(VULKAN_EXCLUDES)
|
||||
LIBAWT_WLAWT_EXCLUDE_FILES := common/awt/X11Color.c common/awt/awt_Font.c
|
||||
|
||||
# Substitute Vulkan with stubs if disabled.
|
||||
ifeq ($(VULKAN_ENABLED), false)
|
||||
LIBAWT_WLAWT_EXCLUDES += vulkan
|
||||
LIBAWT_WLAWT_EXTRA_FILES += $(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan/VKStubs.c
|
||||
endif
|
||||
|
||||
LIBAWT_WLAWT_EXTRA_HEADER_DIRS := \
|
||||
$(LIBAWT_DEFAULT_HEADER_DIRS) \
|
||||
libawt_wlawt/awt \
|
||||
$(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/wayland \
|
||||
include \
|
||||
common/awt/debug \
|
||||
common/awt/systemscale \
|
||||
@@ -1103,8 +1111,7 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
LIBAWT_LWAWT_CFLAGS := $(X_CFLAGS) $(X_LIBS)
|
||||
|
||||
LIBAWT_LWAWT_EXFILES := fontpath.c awt_Font.c X11Color.c
|
||||
LIBAWT_LWAWT_EXCLUDES := \
|
||||
$(TOPDIR)/src/$(MODULE)/share/native/common/java2d/vulkan \
|
||||
LIBAWT_LWAWT_EXCLUDES := $(VULKAN_EXCLUDES) \
|
||||
$(TOPDIR)/src/$(MODULE)/unix/native/common/awt/medialib \
|
||||
#
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ product(bool, UseOSErrorReporting, false, \
|
||||
"Let VM fatal error propagate to the OS (ie. WER on Windows)") \
|
||||
\
|
||||
product(bool, UseCriticalSection, true, EXPERIMENTAL, \
|
||||
"Use the critical section API instead of WaitForSingleObject")
|
||||
"Use the critical section API instead of WaitForSingleObject") \
|
||||
\
|
||||
product(bool, UseModernSynchAPI, true, EXPERIMENTAL, \
|
||||
"Use more modern WinAPI for synchronization instead of WaitForSingleObject")
|
||||
|
||||
// end of RUNTIME_OS_FLAGS
|
||||
|
||||
|
||||
@@ -5805,7 +5805,9 @@ int PlatformEvent::park(jlong Millis) {
|
||||
// 1 => 0 : pass - return immediately
|
||||
// 0 => -1 : block; then set _Event to 0 before returning
|
||||
|
||||
guarantee(_ParkHandle != nullptr , "Invariant");
|
||||
if (!UseModernSynchAPI) {
|
||||
guarantee(_ParkHandle != nullptr , "Invariant");
|
||||
}
|
||||
guarantee(Millis > 0 , "Invariant");
|
||||
|
||||
// CONSIDER: defer assigning a CreateEvent() handle to the Event until
|
||||
@@ -5837,22 +5839,34 @@ int PlatformEvent::park(jlong Millis) {
|
||||
// adjust Millis accordingly if we encounter a spurious wakeup.
|
||||
|
||||
const int MAXTIMEOUT = 0x10000000;
|
||||
DWORD rv = WAIT_TIMEOUT;
|
||||
while (_Event < 0 && Millis > 0) {
|
||||
DWORD prd = Millis; // set prd = MAX (Millis, MAXTIMEOUT)
|
||||
if (Millis > MAXTIMEOUT) {
|
||||
prd = MAXTIMEOUT;
|
||||
}
|
||||
|
||||
if (UseModernSynchAPI) {
|
||||
HighResolutionInterval *phri = nullptr;
|
||||
if (!ForceTimeHighResolution) {
|
||||
phri = new HighResolutionInterval(prd);
|
||||
phri = new HighResolutionInterval(Millis);
|
||||
}
|
||||
rv = ::WaitForSingleObject(_ParkHandle, prd);
|
||||
assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed");
|
||||
if (rv == WAIT_TIMEOUT) {
|
||||
Millis -= prd;
|
||||
if ((v = Atomic::load_acquire(&_Event)) < 0) {
|
||||
::WaitOnAddress(&_Event, &v, sizeof(_Event), Millis);
|
||||
}
|
||||
delete phri; // if it is null, harmless
|
||||
} else {
|
||||
DWORD rv = WAIT_TIMEOUT;
|
||||
while (_Event < 0 && Millis > 0) {
|
||||
DWORD prd = Millis; // set prd = MAX (Millis, MAXTIMEOUT)
|
||||
if (Millis > MAXTIMEOUT) {
|
||||
prd = MAXTIMEOUT;
|
||||
}
|
||||
HighResolutionInterval *phri = nullptr;
|
||||
if (!ForceTimeHighResolution) {
|
||||
phri = new HighResolutionInterval(prd);
|
||||
}
|
||||
rv = ::WaitForSingleObject(_ParkHandle, prd);
|
||||
assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed");
|
||||
if (rv == WAIT_TIMEOUT) {
|
||||
Millis -= prd;
|
||||
}
|
||||
delete phri; // if it is null, harmless
|
||||
}
|
||||
}
|
||||
v = _Event;
|
||||
_Event = 0;
|
||||
@@ -5870,7 +5884,9 @@ void PlatformEvent::park() {
|
||||
// 1 => 0 : pass - return immediately
|
||||
// 0 => -1 : block; then set _Event to 0 before returning
|
||||
|
||||
guarantee(_ParkHandle != nullptr, "Invariant");
|
||||
if (!UseModernSynchAPI) {
|
||||
guarantee(_ParkHandle != nullptr, "Invariant");
|
||||
}
|
||||
// Invariant: Only the thread associated with the Event/PlatformEvent
|
||||
// may call park().
|
||||
// Consider: use atomic decrement instead of CAS-loop
|
||||
@@ -5882,12 +5898,18 @@ void PlatformEvent::park() {
|
||||
guarantee((v == 0) || (v == 1), "invariant");
|
||||
if (v != 0) return;
|
||||
|
||||
// Do this the hard way by blocking ...
|
||||
// TODO: consider a brief spin here, gated on the success of recent
|
||||
// spin attempts by this thread.
|
||||
while (_Event < 0) {
|
||||
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
|
||||
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed");
|
||||
if (UseModernSynchAPI) {
|
||||
while ((v = Atomic::load_acquire(&_Event)) < 0) {
|
||||
::WaitOnAddress(&_Event, &v, sizeof(_Event), INFINITE);
|
||||
}
|
||||
} else {
|
||||
// Do this the hard way by blocking ...
|
||||
// TODO: consider a brief spin here, gated on the success of recent
|
||||
// spin attempts by this thread.
|
||||
while (_Event < 0) {
|
||||
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
|
||||
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed");
|
||||
}
|
||||
}
|
||||
|
||||
// Usually we'll find _Event == 0 at this point, but as
|
||||
@@ -5899,7 +5921,9 @@ void PlatformEvent::park() {
|
||||
}
|
||||
|
||||
void PlatformEvent::unpark() {
|
||||
guarantee(_ParkHandle != nullptr, "Invariant");
|
||||
if (!UseModernSynchAPI) {
|
||||
guarantee(_ParkHandle != nullptr, "Invariant");
|
||||
}
|
||||
|
||||
// Transitions for _Event:
|
||||
// 0 => 1 : just return
|
||||
@@ -5915,9 +5939,14 @@ void PlatformEvent::unpark() {
|
||||
// from the first park() call after an unpark() call which will help
|
||||
// shake out uses of park() and unpark() without condition variables.
|
||||
|
||||
if (Atomic::xchg(&_Event, 1) >= 0) return;
|
||||
|
||||
::SetEvent(_ParkHandle);
|
||||
if (UseModernSynchAPI) {
|
||||
if (Atomic::xchg(&_Event, 1) >= 0) return;
|
||||
// Changed from -1 to 1; the target thread's WaitOnAddress() must return now
|
||||
::WakeByAddressAll((PVOID) &_Event);
|
||||
} else {
|
||||
if (Atomic::xchg(&_Event, 1) >= 0) return;
|
||||
::SetEvent(_ParkHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5929,7 +5958,6 @@ void PlatformEvent::unpark() {
|
||||
// use them directly.
|
||||
|
||||
void Parker::park(bool isAbsolute, jlong time) {
|
||||
guarantee(_ParkHandle != nullptr, "invariant");
|
||||
// First, demultiplex/decode time arguments
|
||||
if (time < 0) { // don't wait
|
||||
return;
|
||||
@@ -5949,23 +5977,50 @@ void Parker::park(bool isAbsolute, jlong time) {
|
||||
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
// Don't wait if interrupted or already triggered
|
||||
if (thread->is_interrupted(false) ||
|
||||
WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) {
|
||||
ResetEvent(_ParkHandle);
|
||||
return;
|
||||
} else {
|
||||
ThreadBlockInVM tbivm(thread);
|
||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||
if (UseModernSynchAPI) {
|
||||
// Don't wait if interrupted or already triggered
|
||||
if (thread->is_interrupted(false)) {
|
||||
Atomic::release_store(&_TargetValue, 0);
|
||||
return;
|
||||
} else {
|
||||
int curHandle = Atomic::load_acquire(&_TargetValue);
|
||||
if (curHandle > 0) {
|
||||
// Already unparked
|
||||
Atomic::release_store(&_TargetValue, 0);
|
||||
return;
|
||||
} else {
|
||||
ThreadBlockInVM tbivm(thread);
|
||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||
|
||||
WaitForSingleObject(_ParkHandle, time);
|
||||
ResetEvent(_ParkHandle);
|
||||
// Spurios wakeups are fine as per Unsafe.park() promise
|
||||
::WaitOnAddress(&_TargetValue, &curHandle, sizeof(_TargetValue), time);
|
||||
Atomic::release_store(&_TargetValue, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Don't wait if interrupted or already triggered
|
||||
if (thread->is_interrupted(false) ||
|
||||
WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) {
|
||||
ResetEvent(_ParkHandle);
|
||||
return;
|
||||
} else {
|
||||
ThreadBlockInVM tbivm(thread);
|
||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||
|
||||
WaitForSingleObject(_ParkHandle, time);
|
||||
ResetEvent(_ParkHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Parker::unpark() {
|
||||
guarantee(_ParkHandle != nullptr, "invariant");
|
||||
SetEvent(_ParkHandle);
|
||||
if (UseModernSynchAPI) {
|
||||
Atomic::release_store(&_TargetValue, 1);
|
||||
::WakeByAddressAll(&_TargetValue);
|
||||
} else {
|
||||
guarantee(_ParkHandle != nullptr, "invariant");
|
||||
SetEvent(_ParkHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// Platform Monitor implementation
|
||||
|
||||
@@ -41,8 +41,10 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||
public:
|
||||
PlatformEvent() {
|
||||
_Event = 0 ;
|
||||
_ParkHandle = CreateEvent (nullptr, false, false, nullptr) ;
|
||||
guarantee (_ParkHandle != nullptr, "invariant") ;
|
||||
if (!UseModernSynchAPI) {
|
||||
_ParkHandle = CreateEvent (nullptr, false, false, nullptr) ;
|
||||
guarantee (_ParkHandle != nullptr, "invariant") ;
|
||||
}
|
||||
}
|
||||
|
||||
// Exercise caution using reset() and fired() - they may require MEMBARs
|
||||
@@ -57,16 +59,23 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||
class PlatformParker {
|
||||
NONCOPYABLE(PlatformParker);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
HANDLE _ParkHandle;
|
||||
int _TargetValue;
|
||||
|
||||
public:
|
||||
public:
|
||||
PlatformParker() {
|
||||
_ParkHandle = CreateEvent (nullptr, true, false, nullptr) ;
|
||||
guarantee(_ParkHandle != nullptr, "invariant") ;
|
||||
if (UseModernSynchAPI) {
|
||||
_TargetValue = 0;
|
||||
} else {
|
||||
_ParkHandle = CreateEvent (nullptr, true, false, nullptr) ;
|
||||
guarantee(_ParkHandle != nullptr, "invariant") ;
|
||||
}
|
||||
}
|
||||
~PlatformParker() {
|
||||
CloseHandle(_ParkHandle);
|
||||
if (! UseModernSynchAPI) {
|
||||
CloseHandle(_ParkHandle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -404,7 +404,6 @@ bool SharedClassPathEntry::validate(bool is_class_path) const {
|
||||
// filters out any archived module classes that do not have a matching runtime
|
||||
// module path location.
|
||||
log_warning(cds)("Required classpath entry does not exist: %s", name);
|
||||
ok = false;
|
||||
} else if (is_dir()) {
|
||||
if (!os::dir_is_empty(name)) {
|
||||
log_warning(cds)("directory is not empty: %s", name);
|
||||
@@ -844,6 +843,20 @@ bool FileMapInfo::validate_boot_class_paths() {
|
||||
num = rp_len;
|
||||
}
|
||||
mismatch = check_paths(1, num, rp_array, 0, 0);
|
||||
if (mismatch) {
|
||||
// To facilitate app deployment, we allow the JAR files to be moved *together* to
|
||||
// a different location, as long as they are still stored under the same directory
|
||||
// structure. E.g., the following is OK.
|
||||
// Extends JDK-8279366 to boot classpath.
|
||||
unsigned int dumptime_prefix_len = header()->common_app_classpath_prefix_size();
|
||||
unsigned int runtime_prefix_len = longest_common_app_classpath_prefix_len(num, rp_array);
|
||||
if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) {
|
||||
log_info(cds, path)("LCP length for boot classpath (dumptime: %u, runtime: %u)",
|
||||
dumptime_prefix_len, runtime_prefix_len);
|
||||
mismatch = check_paths(1, num, rp_array,
|
||||
dumptime_prefix_len, runtime_prefix_len);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths
|
||||
// are the same initially, after the call to create_path_array(), the runtime boot classpath length could become
|
||||
|
||||
@@ -34,17 +34,31 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
#include "runtime/fieldDescriptor.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
|
||||
DcevmSharedGC* DcevmSharedGC::_static_instance = nullptr;
|
||||
|
||||
void DcevmSharedGC::create_static_instance() {
|
||||
_static_instance = new DcevmSharedGC();
|
||||
}
|
||||
|
||||
void DcevmSharedGC::destroy_static_instance() {
|
||||
if (_static_instance != nullptr) {
|
||||
delete _static_instance;
|
||||
_static_instance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, bool must_be_new) {
|
||||
if (rescued_oops != NULL) {
|
||||
if (rescued_oops != nullptr) {
|
||||
copy_rescued_objects_back(rescued_oops, 0, rescued_oops->length(), must_be_new);
|
||||
}
|
||||
}
|
||||
|
||||
// (DCEVM) Copy the rescued objects to their destination address after compaction.
|
||||
void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, int from, int to, bool must_be_new) {
|
||||
|
||||
if (rescued_oops != NULL) {
|
||||
if (rescued_oops != nullptr) {
|
||||
for (int i=from; i < to; i++) {
|
||||
HeapWord* rescued_ptr = rescued_oops->at(i);
|
||||
oop rescued_obj = cast_to_oop(rescued_ptr);
|
||||
@@ -52,10 +66,10 @@ void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_
|
||||
size_t size = rescued_obj->size();
|
||||
oop new_obj = rescued_obj->forwardee();
|
||||
|
||||
assert(!must_be_new || rescued_obj->klass()->new_version() != NULL, "Just checking");
|
||||
assert(!must_be_new || rescued_obj->klass()->new_version() != nullptr, "Just checking");
|
||||
Klass* new_klass = rescued_obj->klass()->new_version();
|
||||
if (new_klass!= NULL) {
|
||||
if (new_klass->update_information() != NULL) {
|
||||
if (new_klass!= nullptr) {
|
||||
if (new_klass->update_information() != nullptr) {
|
||||
DcevmSharedGC::update_fields(rescued_obj, new_obj);
|
||||
} else {
|
||||
rescued_obj->set_klass(new_klass);
|
||||
@@ -69,11 +83,10 @@ void DcevmSharedGC::copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_
|
||||
assert(oopDesc::is_oop(new_obj), "must be a valid oop");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DcevmSharedGC::clear_rescued_objects_resource(GrowableArray<HeapWord*>* rescued_oops) {
|
||||
if (rescued_oops != NULL) {
|
||||
if (rescued_oops != nullptr) {
|
||||
for (int i=0; i < rescued_oops->length(); i++) {
|
||||
HeapWord* rescued_ptr = rescued_oops->at(i);
|
||||
size_t size = cast_to_oop(rescued_ptr)->size();
|
||||
@@ -84,7 +97,7 @@ void DcevmSharedGC::clear_rescued_objects_resource(GrowableArray<HeapWord*>* res
|
||||
}
|
||||
|
||||
void DcevmSharedGC::clear_rescued_objects_heap(GrowableArray<HeapWord*>* rescued_oops) {
|
||||
if (rescued_oops != NULL) {
|
||||
if (rescued_oops != nullptr) {
|
||||
for (int i=0; i < rescued_oops->length(); i++) {
|
||||
HeapWord* rescued_ptr = rescued_oops->at(i);
|
||||
FREE_C_HEAP_ARRAY(HeapWord, rescued_ptr);
|
||||
@@ -96,7 +109,7 @@ void DcevmSharedGC::clear_rescued_objects_heap(GrowableArray<HeapWord*>* rescued
|
||||
// (DCEVM) Update instances of a class whose fields changed.
|
||||
void DcevmSharedGC::update_fields(oop q, oop new_location) {
|
||||
|
||||
assert(q->klass()->new_version() != NULL, "class of old object must have new version");
|
||||
assert(q->klass()->new_version() != nullptr, "class of old object must have new version");
|
||||
|
||||
Klass* old_klass_oop = q->klass();
|
||||
Klass* new_klass_oop = q->klass()->new_version();
|
||||
@@ -107,7 +120,7 @@ void DcevmSharedGC::update_fields(oop q, oop new_location) {
|
||||
size_t size = q->size_given_klass(old_klass);
|
||||
size_t new_size = q->size_given_klass(new_klass);
|
||||
|
||||
HeapWord* tmp = NULL;
|
||||
HeapWord* tmp = nullptr;
|
||||
oop tmp_obj = q;
|
||||
|
||||
// Save object somewhere, there is an overlap in fields
|
||||
@@ -122,39 +135,141 @@ void DcevmSharedGC::update_fields(oop q, oop new_location) {
|
||||
|
||||
q->set_klass(new_klass_oop);
|
||||
int *cur = new_klass_oop->update_information();
|
||||
assert(cur != NULL, "just checking");
|
||||
DcevmSharedGC::update_fields(new_location, q, cur);
|
||||
assert(cur != nullptr, "just checking");
|
||||
_static_instance->update_fields(new_location, q, cur, false);
|
||||
|
||||
if (tmp != NULL) {
|
||||
if (tmp != nullptr) {
|
||||
FREE_RESOURCE_ARRAY(HeapWord, tmp, size);
|
||||
}
|
||||
}
|
||||
|
||||
void DcevmSharedGC::update_fields(oop new_location, oop tmp_obj, int *cur) {
|
||||
assert(cur != NULL, "just checking");
|
||||
char* to = (char*)cast_from_oop<HeapWord*>(new_location);
|
||||
void DcevmSharedGC::update_fields(oop new_obj, oop old_obj, int* cur, bool do_compat_check) {
|
||||
assert(cur != nullptr, "just checking");
|
||||
char* to = (char*)cast_from_oop<HeapWord*>(new_obj);
|
||||
char* src_base = (char *)cast_from_oop<HeapWord*>(old_obj);
|
||||
while (*cur != 0) {
|
||||
int size = *cur;
|
||||
if (size > 0) {
|
||||
int raw = *cur;
|
||||
if (raw > 0) {
|
||||
cur++;
|
||||
int offset = *cur;
|
||||
HeapWord* from = (HeapWord*)(((char *)cast_from_oop<HeapWord*>(tmp_obj)) + offset);
|
||||
if (size == HeapWordSize) {
|
||||
*((HeapWord*)to) = *from;
|
||||
} else if (size == HeapWordSize * 2) {
|
||||
*((HeapWord*)to) = *from;
|
||||
*(((HeapWord*)to) + 1) = *(from + 1);
|
||||
int src_offset = *cur;
|
||||
HeapWord* from = (HeapWord*)(src_base + src_offset);
|
||||
|
||||
bool compat_check = do_compat_check && ((raw & UpdateInfoCompatFlag) != 0);
|
||||
int size = (raw & UpdateInfoLengthMask);
|
||||
|
||||
if (!compat_check) {
|
||||
if (size == HeapWordSize) {
|
||||
*((HeapWord *) to) = *from;
|
||||
} else if (size == HeapWordSize * 2) {
|
||||
*((HeapWord *) to) = *from;
|
||||
*(((HeapWord *) to) + 1) = *(from + 1);
|
||||
} else {
|
||||
Copy::conjoint_jbytes(from, to, size);
|
||||
}
|
||||
} else {
|
||||
Copy::conjoint_jbytes(from, to, size);
|
||||
assert(size == heapOopSize, "Must be one oop");
|
||||
int dst_offset = (int)(to - (char*)cast_from_oop<HeapWord*>(new_obj));
|
||||
|
||||
oop obj = old_obj->obj_field(src_offset);
|
||||
|
||||
if (obj == nullptr) {
|
||||
new_obj->obj_field_put(dst_offset, nullptr);
|
||||
} else {
|
||||
bool compatible = is_compatible(new_obj, dst_offset, obj);
|
||||
new_obj->obj_field_put(dst_offset, compatible ? obj : (oop)nullptr);
|
||||
}
|
||||
}
|
||||
to += size;
|
||||
cur++;
|
||||
} else {
|
||||
assert(size < 0, "");
|
||||
int skip = -*cur;
|
||||
Copy::fill_to_bytes(to, skip, 0);
|
||||
to += skip;
|
||||
Copy::fill_to_bytes(to, -raw, 0);
|
||||
to += -raw;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DcevmSharedGC::update_fields_in_old(oop old_obj, int* cur) {
|
||||
assert(cur != nullptr, "just checking");
|
||||
int dst_offset = 0;
|
||||
while (*cur != 0) {
|
||||
int raw = *cur;
|
||||
if (raw > 0) {
|
||||
cur++;
|
||||
int size = (raw & UpdateInfoLengthMask);
|
||||
|
||||
if ((raw & UpdateInfoCompatFlag) != 0) {
|
||||
assert(size == heapOopSize, "Must be one oop");
|
||||
int src_offset = *cur;
|
||||
oop obj = old_obj->obj_field(src_offset);
|
||||
if (obj != nullptr) {
|
||||
bool compatible = is_compatible(old_obj, dst_offset, obj);
|
||||
if (!compatible) {
|
||||
old_obj->obj_field_put(src_offset, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
dst_offset += size;
|
||||
cur++;
|
||||
} else {
|
||||
dst_offset += -raw;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool signature_matches_name(Symbol* sig, Symbol* name) {
|
||||
const int sig_len = sig->utf8_length();
|
||||
const int name_len = name->utf8_length();
|
||||
if (sig_len != name_len + 2) {
|
||||
return false;
|
||||
}
|
||||
const u1* s = sig ->bytes();
|
||||
const u1* n = name->bytes();
|
||||
return (s[0] == 'L' && s[sig_len - 1] == ';' && memcmp(s + 1, n, name_len) == 0);
|
||||
}
|
||||
|
||||
bool DcevmSharedGC::is_compatible(oop fld_holder, int fld_offset, oop fld_val) {
|
||||
assert(oopDesc::is_oop(fld_val), "val has corrupted header");
|
||||
|
||||
bool result = false;
|
||||
Symbol *sig_wanted;
|
||||
|
||||
InstanceKlass* holder_ik = InstanceKlass::cast(fld_holder->klass()->newest_version());
|
||||
Symbol** sig_cached = _field_sig_table->get({holder_ik, fld_offset});
|
||||
|
||||
if (sig_cached != nullptr) {
|
||||
sig_wanted = *sig_cached;
|
||||
} else {
|
||||
fieldDescriptor fd_new;
|
||||
bool ok = holder_ik->find_field_from_offset(fld_offset, false, &fd_new);
|
||||
assert(ok, "Must exist");
|
||||
sig_wanted = fd_new.signature();
|
||||
_field_sig_table->put({holder_ik, fld_offset}, sig_wanted);
|
||||
}
|
||||
|
||||
InstanceKlass *ik = InstanceKlass::cast(fld_val->klass()->newest_version());
|
||||
bool* hit = _compat_table->get({ik, sig_wanted });
|
||||
|
||||
if (hit != nullptr) {
|
||||
result = *hit;
|
||||
} else {
|
||||
InstanceKlass* scan = ik;
|
||||
while (scan != nullptr && !result) {
|
||||
if (signature_matches_name(sig_wanted, scan->name())) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
Array<InstanceKlass*>* ifaces = scan->local_interfaces();
|
||||
for (int j = 0; j < ifaces->length(); ++j) {
|
||||
if (signature_matches_name(sig_wanted, ifaces->at(j)->name())) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
scan = (scan->super() != nullptr) ? InstanceKlass::cast(scan->super()) : nullptr;
|
||||
}
|
||||
_compat_table->put({ik, sig_wanted }, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -33,16 +33,76 @@
|
||||
#include "runtime/timer.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/stack.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
|
||||
// Shared GC code used from different GC (Serial, CMS, G1) on enhanced redefinition
|
||||
class DcevmSharedGC : AllStatic {
|
||||
public:
|
||||
class DcevmSharedGC : public CHeapObj<mtInternal> {
|
||||
private:
|
||||
struct SymbolKey {
|
||||
InstanceKlass* ik;
|
||||
Symbol* dst_sig;
|
||||
};
|
||||
static unsigned symbol_hash(const SymbolKey& k) {
|
||||
return (uintptr_t)k.ik ^ (uintptr_t)k.dst_sig;
|
||||
}
|
||||
static bool symbol_eq(const SymbolKey& a, const SymbolKey& b) {
|
||||
return a.ik == b.ik && a.dst_sig == b.dst_sig;
|
||||
}
|
||||
typedef ResourceHashtable<SymbolKey, bool, 512,
|
||||
AnyObj::C_HEAP, mtInternal,
|
||||
&symbol_hash, &symbol_eq> CompatTable;
|
||||
|
||||
struct OffsetKey {
|
||||
InstanceKlass* ik;
|
||||
int offset;
|
||||
};
|
||||
static unsigned offset_hash(const OffsetKey& k) {
|
||||
return uintptr_t(k.ik) ^ k.offset;
|
||||
}
|
||||
static bool offset_eq(const OffsetKey& a, const OffsetKey& b) {
|
||||
return a.ik == b.ik && a.offset == b.offset;
|
||||
}
|
||||
typedef ResourceHashtable<OffsetKey, Symbol*, 512,
|
||||
AnyObj::C_HEAP, mtInternal,
|
||||
&offset_hash, &offset_eq> FieldSigTable;
|
||||
|
||||
CompatTable* _compat_table;
|
||||
FieldSigTable* _field_sig_table;
|
||||
static DcevmSharedGC* _static_instance;
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------
|
||||
// update info flags
|
||||
//
|
||||
// bit 31 : sign bit (<0 = fill, >0 = copy)
|
||||
// bit 30 : UpdateInfoCompatFlag – copy segment requires per-oop compatibility check
|
||||
// bits 0-29 : raw byte length of the segment
|
||||
// ------------------------------------------------------------------
|
||||
static const int UpdateInfoCompatFlag = 1U << 30;
|
||||
static const int UpdateInfoLengthMask = ~(1U << 31 | UpdateInfoCompatFlag);
|
||||
|
||||
DcevmSharedGC() {
|
||||
_compat_table = new (mtInternal) CompatTable();
|
||||
_field_sig_table = new (mtInternal) FieldSigTable();
|
||||
}
|
||||
|
||||
~DcevmSharedGC() {
|
||||
delete _compat_table;
|
||||
delete _field_sig_table;
|
||||
}
|
||||
|
||||
static void create_static_instance();
|
||||
static void destroy_static_instance();
|
||||
|
||||
static void copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, bool must_be_new);
|
||||
static void copy_rescued_objects_back(GrowableArray<HeapWord*>* rescued_oops, int from, int to, bool must_be_new);
|
||||
static void clear_rescued_objects_resource(GrowableArray<HeapWord*>* rescued_oops);
|
||||
static void clear_rescued_objects_heap(GrowableArray<HeapWord*>* rescued_oops);
|
||||
static void update_fields(oop q, oop new_location);
|
||||
static void update_fields(oop new_location, oop tmp_obj, int *cur);
|
||||
|
||||
bool is_compatible(oop fld_holder, int fld_offset, oop fld_val);
|
||||
void update_fields(oop new_obj, oop old_obj, int *cur, bool do_compat_check);
|
||||
void update_fields_in_old(oop old_obj, int *cur);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -93,7 +93,9 @@ class SATBMarkQueueSet: public PtrQueueSet {
|
||||
size_t _buffer_enqueue_threshold;
|
||||
// SATB is only active during marking. Enqueuing is only done when active.
|
||||
bool _all_active;
|
||||
DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 4 * sizeof(size_t));
|
||||
#if ! (defined(_WIN64) && DEFAULT_CACHE_LINE_SIZE == 32)
|
||||
DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, 4 * sizeof(size_t));
|
||||
#endif
|
||||
|
||||
BufferNode* get_completed_buffer();
|
||||
void abandon_completed_buffers();
|
||||
|
||||
@@ -369,18 +369,6 @@ void ConstantPool::remove_unshareable_info() {
|
||||
// we always set _on_stack to true to avoid having to change _flags during runtime.
|
||||
_flags |= (_on_stack | _is_shared);
|
||||
|
||||
if (!_pool_holder->is_linked() && !_pool_holder->verified_at_dump_time()) {
|
||||
return;
|
||||
}
|
||||
// Resolved references are not in the shared archive.
|
||||
// Save the length for restoration. It is not necessarily the same length
|
||||
// as reference_map.length() if invokedynamic is saved. It is needed when
|
||||
// re-creating the resolved reference array if archived heap data cannot be map
|
||||
// at runtime.
|
||||
set_resolved_reference_length(
|
||||
resolved_references() != nullptr ? resolved_references()->length() : 0);
|
||||
set_resolved_references(OopHandle());
|
||||
|
||||
bool archived = false;
|
||||
for (int index = 1; index < length(); index++) { // Index 0 is unused
|
||||
switch (tag_at(index).value()) {
|
||||
@@ -403,6 +391,19 @@ void ConstantPool::remove_unshareable_info() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!_pool_holder->is_linked() && !_pool_holder->verified_at_dump_time()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolved references are not in the shared archive.
|
||||
// Save the length for restoration. It is not necessarily the same length
|
||||
// as reference_map.length() if invokedynamic is saved. It is needed when
|
||||
// re-creating the resolved reference array if archived heap data cannot be map
|
||||
// at runtime.
|
||||
set_resolved_reference_length(
|
||||
resolved_references() != nullptr ? resolved_references()->length() : 0);
|
||||
set_resolved_references(OopHandle());
|
||||
|
||||
if (cache() != nullptr) {
|
||||
// cache() is null if this class is not yet linked.
|
||||
cache()->remove_unshareable_info();
|
||||
|
||||
@@ -371,6 +371,11 @@ void InstanceKlass::set_nest_host(InstanceKlass* host) {
|
||||
// Can't assert this as package is not set yet:
|
||||
// assert(is_same_class_package(host), "proposed host is in wrong package");
|
||||
|
||||
// set dynamic nest host
|
||||
_nest_host = host;
|
||||
// Record dependency to keep nest host from being unloaded before this class.
|
||||
ClassLoaderData* this_key = class_loader_data();
|
||||
|
||||
if (log_is_enabled(Trace, class, nestmates)) {
|
||||
ResourceMark rm;
|
||||
const char* msg = "";
|
||||
@@ -379,18 +384,19 @@ void InstanceKlass::set_nest_host(InstanceKlass* host) {
|
||||
msg = "(the NestHost attribute in the current class is ignored)";
|
||||
} else if (_nest_members != nullptr && _nest_members != Universe::the_empty_short_array()) {
|
||||
msg = "(the NestMembers attribute in the current class is ignored)";
|
||||
} else if (this_key == nullptr) {
|
||||
msg = "(the NestMembers classloader data in the current class is ignored)";
|
||||
}
|
||||
|
||||
log_trace(class, nestmates)("Injected type %s into the nest of %s %s",
|
||||
this->external_name(),
|
||||
host->external_name(),
|
||||
msg);
|
||||
}
|
||||
// set dynamic nest host
|
||||
_nest_host = host;
|
||||
// Record dependency to keep nest host from being unloaded before this class.
|
||||
ClassLoaderData* this_key = class_loader_data();
|
||||
assert(this_key != nullptr, "sanity");
|
||||
this_key->record_dependency(host);
|
||||
|
||||
if (this_key != nullptr) {
|
||||
this_key->record_dependency(host);
|
||||
}
|
||||
}
|
||||
|
||||
// check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
|
||||
@@ -1781,6 +1787,18 @@ bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDesc
|
||||
}
|
||||
|
||||
|
||||
bool InstanceKlass::find_local_field_by_name(Symbol* name, fieldDescriptor* fd) const {
|
||||
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
|
||||
Symbol* f_name = fs.name();
|
||||
if (f_name == name) {
|
||||
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void InstanceKlass::methods_do(void f(Method* method)) {
|
||||
// Methods aren't stable until they are loaded. This can be read outside
|
||||
// a lock through the ClassLoaderData for profiling
|
||||
|
||||
@@ -566,6 +566,7 @@ public:
|
||||
bool find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
|
||||
bool find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
|
||||
|
||||
bool find_local_field_by_name(Symbol* name, fieldDescriptor* fd) const;
|
||||
private:
|
||||
inline static int quick_search(const Array<Method*>* methods, const Symbol* name);
|
||||
|
||||
|
||||
@@ -196,13 +196,14 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word
|
||||
// The constructor is also used from CppVtableCloner,
|
||||
// which doesn't zero out the memory before calling the constructor.
|
||||
Klass::Klass(KlassKind kind) : _kind(kind),
|
||||
_old_version(NULL),
|
||||
_new_version(NULL),
|
||||
_old_version(nullptr),
|
||||
_new_version(nullptr),
|
||||
_redefinition_flags(Klass::NoRedefinition),
|
||||
_is_redefining(false),
|
||||
_update_information(NULL),
|
||||
_update_information(nullptr),
|
||||
_is_copying_backwards(false),
|
||||
_is_rolled_back(false),
|
||||
_compat_check_field_offsets(nullptr),
|
||||
_shared_class_path_index(-1) {
|
||||
CDS_ONLY(_shared_class_flags = 0;)
|
||||
CDS_JAVA_HEAP_ONLY(_archived_mirror_index = -1;)
|
||||
|
||||
@@ -167,18 +167,18 @@ class Klass : public Metadata {
|
||||
|
||||
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
|
||||
|
||||
// Advanced class redefinition
|
||||
|
||||
// Enhanced class redefinition
|
||||
// Old version (used in advanced class redefinition)
|
||||
Klass* _old_version;
|
||||
// New version (used in advanced class redefinition)
|
||||
Klass* _new_version;
|
||||
|
||||
int _redefinition_flags; // Level of class redefinition
|
||||
bool _is_redefining;
|
||||
int* _update_information;
|
||||
bool _is_copying_backwards; // Does the class need to copy fields backwards? => possibly overwrite itself?
|
||||
bool _is_rolled_back; // true if class was rolled back in redefinition
|
||||
// offsets of fields used in compatibility check
|
||||
GrowableArray<int>* volatile _compat_check_field_offsets;
|
||||
|
||||
private:
|
||||
// This is an index into FileMapHeader::_shared_path_table[], to
|
||||
@@ -419,6 +419,13 @@ protected:
|
||||
void set_copying_backwards(bool b) { _is_copying_backwards = b; }
|
||||
bool is_rolled_back() { return _is_rolled_back; }
|
||||
void set_rolled_back(bool b) { _is_rolled_back = b;}
|
||||
GrowableArray<int>* compat_check_field_offsets() const { return Atomic::load_acquire(&_compat_check_field_offsets); }
|
||||
GrowableArray<int>* set_compat_check_field_offsets(GrowableArray<int>* offsets) {
|
||||
return Atomic::cmpxchg(&_compat_check_field_offsets, (GrowableArray<int>*) nullptr, offsets);
|
||||
}
|
||||
void clear_compat_check_field_offsets() {
|
||||
_compat_check_field_offsets = nullptr;
|
||||
}
|
||||
|
||||
protected: // internal accessors
|
||||
void set_subklass(Klass* s);
|
||||
@@ -431,7 +438,8 @@ protected:
|
||||
ModifyClassSize = ModifyClass << 1, // The size of the class meta data changes.
|
||||
ModifyInstances = ModifyClassSize << 1, // There are change to the instance format.
|
||||
ModifyInstanceSize = ModifyInstances << 1, // The size of instances changes.
|
||||
RemoveSuperType = ModifyInstanceSize << 1, // A super type of this class is removed.
|
||||
RemoveInterface = ModifyInstanceSize << 1, // A super type of this class is removed.
|
||||
RemoveSuperType = RemoveInterface << 1, // A super type of this class is removed.
|
||||
MarkedAsAffected = RemoveSuperType << 1, // This class has been marked as an affected class.
|
||||
PrimaryRedefine = MarkedAsAffected << 1 // This class is from primary redefinition set
|
||||
};
|
||||
|
||||
@@ -108,6 +108,7 @@ VM_EnhancedRedefineClasses::VM_EnhancedRedefineClasses(jint class_count, const j
|
||||
VM_GC_Operation(Universe::heap()->total_collections(), GCCause::_heap_inspection, Universe::heap()->total_full_collections(), true) {
|
||||
_new_classes = nullptr;
|
||||
_affected_klasses = nullptr;
|
||||
_removed_interfaces = nullptr;
|
||||
_class_count = class_count;
|
||||
_class_defs = class_defs;
|
||||
_class_load_kind = class_load_kind;
|
||||
@@ -128,7 +129,6 @@ static inline InstanceKlass* get_ik(jclass def) {
|
||||
// - Start mark&sweep GC.
|
||||
// - true if success, otherwise all chnages are rollbacked.
|
||||
bool VM_EnhancedRedefineClasses::doit_prologue() {
|
||||
|
||||
if (_class_count == 0) {
|
||||
_res = JVMTI_ERROR_NONE;
|
||||
return false;
|
||||
@@ -202,7 +202,36 @@ bool VM_EnhancedRedefineClasses::doit_prologue() {
|
||||
|
||||
// Closer for static fields - copy value from old class to the new class.
|
||||
class FieldCopier : public FieldClosure {
|
||||
public:
|
||||
private:
|
||||
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
|
||||
public:
|
||||
FieldCopier(VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
|
||||
: _removed_interfaces(removed_interfaces) {}
|
||||
|
||||
bool is_compatible(oop fld_holder, int fld_offset, Symbol* sig_new) {
|
||||
oop oop = fld_holder->obj_field(fld_offset);
|
||||
if (oop != nullptr) {
|
||||
Klass* k = oop->klass();
|
||||
if (k->is_instance_klass() && k->is_redefining()) {
|
||||
InstanceKlass *scan = InstanceKlass::cast(k);
|
||||
while (scan != nullptr) {
|
||||
if (sig_new->equals(scan->signature_name())) {
|
||||
return true;
|
||||
}
|
||||
Array<InstanceKlass*>* local_interfaces = scan->local_interfaces();
|
||||
for (int j = 0; j < local_interfaces->length(); j++) {
|
||||
Klass* iface = local_interfaces->at(j);
|
||||
if (sig_new->equals(iface->signature_name())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
scan = (scan->super() != nullptr) ? InstanceKlass::cast(scan->super()) : nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void do_field(fieldDescriptor* fd) {
|
||||
InstanceKlass* cur = InstanceKlass::cast(fd->field_holder());
|
||||
oop cur_oop = cur->java_mirror();
|
||||
@@ -211,19 +240,36 @@ class FieldCopier : public FieldClosure {
|
||||
oop old_oop = old->java_mirror();
|
||||
|
||||
fieldDescriptor result;
|
||||
bool found = old->find_local_field(fd->name(), fd->signature(), &result);
|
||||
Symbol* sig_new = fd->signature();
|
||||
bool found = old->find_local_field_by_name(fd->name(), &result);
|
||||
if (found && result.is_static()) {
|
||||
log_trace(redefine, class, obsolete, metadata)("Copying static field value for field %s old_offset=%d new_offset=%d",
|
||||
fd->name()->as_C_string(), result.offset(), fd->offset());
|
||||
memcpy(cur_oop->field_addr<HeapWord>(fd->offset()),
|
||||
old_oop->field_addr<HeapWord>(result.offset()),
|
||||
type2aelembytes(fd->field_type()));
|
||||
Symbol* sig_old = result.signature();
|
||||
bool compatible = false;
|
||||
|
||||
// Static fields may have references to java.lang.Class
|
||||
if (fd->field_type() == T_OBJECT) {
|
||||
oop oop = cur_oop->obj_field(fd->offset());
|
||||
if (oop != nullptr && oop->is_instance() && InstanceKlass::cast(oop->klass())->is_mirror_instance_klass()) {
|
||||
Klass* klass = java_lang_Class::as_Klass(oop);
|
||||
if (sig_new == sig_old) {
|
||||
if (_removed_interfaces != nullptr && _removed_interfaces->contains(sig_old) && fd->field_type() == T_OBJECT && result.field_type() == T_OBJECT) {
|
||||
compatible = is_compatible(old_oop, result.offset(), sig_new);
|
||||
} else {
|
||||
compatible = true;
|
||||
}
|
||||
} else {
|
||||
if (fd->field_type() == T_OBJECT && result.field_type() == T_OBJECT) {
|
||||
compatible = is_compatible(old_oop, result.offset(), sig_new);
|
||||
}
|
||||
}
|
||||
|
||||
if (compatible) {
|
||||
log_trace(redefine, class, obsolete, metadata)("Copying static field value for field %s old_offset=%d new_offset=%d",
|
||||
fd->name()->as_C_string(), result.offset(), fd->offset());
|
||||
memcpy(cur_oop->field_addr<HeapWord>(fd->offset()),
|
||||
old_oop->field_addr<HeapWord>(result.offset()),
|
||||
type2aelembytes(fd->field_type()));
|
||||
|
||||
// Static fields may have references to java.lang.Class
|
||||
if (fd->field_type() == T_OBJECT) {
|
||||
oop oop = cur_oop->obj_field(fd->offset());
|
||||
if (oop != nullptr && oop->is_instance() && InstanceKlass::cast(oop->klass())->is_mirror_instance_klass()) {
|
||||
Klass *klass = java_lang_Class::as_Klass(oop);
|
||||
if (klass != nullptr && klass->is_instance_klass()) {
|
||||
assert(oop == InstanceKlass::cast(klass)->java_mirror(), "just checking");
|
||||
if (klass->new_version() != nullptr) {
|
||||
@@ -233,10 +279,36 @@ class FieldCopier : public FieldClosure {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_trace(redefine,class, obsolete, metadata)("Skipping incompatible static field %s, old_signature=%s, new_signature=%s",
|
||||
fd->name()->as_C_string(), sig_old->as_C_string(), sig_new->as_C_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FieldCompatibilityChecker : public FieldClosure {
|
||||
private:
|
||||
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
|
||||
GrowableArray<int>* _compat_check_field_offsets;
|
||||
public:
|
||||
FieldCompatibilityChecker(VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
|
||||
: _removed_interfaces(removed_interfaces), _compat_check_field_offsets(nullptr) {}
|
||||
|
||||
void do_field(fieldDescriptor* fd) {
|
||||
Symbol *sig_new = fd->signature();
|
||||
if (_removed_interfaces->contains(fd->signature())) {
|
||||
if (_compat_check_field_offsets == nullptr) {
|
||||
_compat_check_field_offsets = new (mtInternal) GrowableArray<int>(2, mtInternal);
|
||||
}
|
||||
_compat_check_field_offsets->append(fd->offset());
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArray<int>* compat_check_field_offsets() {
|
||||
return _compat_check_field_offsets;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: review...
|
||||
void VM_EnhancedRedefineClasses::mark_as_scavengable(nmethod* nm) {
|
||||
@@ -442,15 +514,23 @@ class ChangePointersOopClosure : public BasicOopIterateClosure {
|
||||
// - otherwise set the _needs_instance_update flag, we need to do full GC
|
||||
// and reshuffle object positions durring mark&sweep
|
||||
class ChangePointersObjectClosure : public ObjectClosure {
|
||||
private:
|
||||
|
||||
private:
|
||||
OopIterateClosure *_closure;
|
||||
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
|
||||
DcevmSharedGC* _dcevm_shared_gc;
|
||||
bool _needs_instance_update;
|
||||
oop _tmp_obj;
|
||||
size_t _tmp_obj_size;
|
||||
|
||||
public:
|
||||
ChangePointersObjectClosure(OopIterateClosure *closure) : _closure(closure), _needs_instance_update(false), _tmp_obj(nullptr), _tmp_obj_size(0) {}
|
||||
ChangePointersObjectClosure(OopIterateClosure *closure, VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
|
||||
: _closure(closure), _removed_interfaces(removed_interfaces), _needs_instance_update(false), _tmp_obj(nullptr), _tmp_obj_size(0) {
|
||||
_dcevm_shared_gc = new DcevmSharedGC();
|
||||
}
|
||||
|
||||
~ChangePointersObjectClosure() {
|
||||
delete _dcevm_shared_gc;
|
||||
}
|
||||
|
||||
bool needs_instance_update() {
|
||||
return _needs_instance_update;
|
||||
@@ -465,6 +545,36 @@ public:
|
||||
Copy::aligned_disjoint_words(cast_from_oop<HeapWord*>(o), cast_from_oop<HeapWord*>(_tmp_obj), size);
|
||||
}
|
||||
|
||||
void do_compat_check_field_offsets(oop obj) {
|
||||
// Non-redefined class may store fields of redefined types
|
||||
// check field-level compatibility to avoid invalid accesses.
|
||||
GrowableArray<int>* fields = obj->klass()->compat_check_field_offsets();
|
||||
if (fields == nullptr) {
|
||||
FieldCompatibilityChecker fld_compat_check(_removed_interfaces);
|
||||
InstanceKlass::cast(obj->klass())->do_nonstatic_fields(&fld_compat_check);
|
||||
fields = fld_compat_check.compat_check_field_offsets();
|
||||
if (fields != nullptr) {
|
||||
GrowableArray<int>* old = obj->klass()->set_compat_check_field_offsets(fields);
|
||||
if (old != nullptr) {
|
||||
delete fields;
|
||||
fields = old;
|
||||
}
|
||||
} else {
|
||||
fields = reinterpret_cast<GrowableArray<int>*>(-1);
|
||||
obj->klass()->set_compat_check_field_offsets(fields);
|
||||
}
|
||||
}
|
||||
if (reinterpret_cast<intptr_t>(fields) != -1) {
|
||||
for (int i = 0; i < fields->length(); i++) {
|
||||
int fld_offset = fields->at(i);
|
||||
oop fld_val = obj->obj_field(fld_offset);
|
||||
if (fld_val != nullptr && !_dcevm_shared_gc->is_compatible(obj, fld_offset, fld_val)) {
|
||||
obj->obj_field_put(fld_offset, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void do_object(oop obj) {
|
||||
if (obj->is_instance() && InstanceKlass::cast(obj->klass())->is_mirror_instance_klass()) {
|
||||
// static fields may have references to old java.lang.Class instances, update them
|
||||
@@ -473,6 +583,9 @@ public:
|
||||
//instanceMirrorKlass::oop_fields_iterate(obj, _closure);
|
||||
} else {
|
||||
obj->oop_iterate(_closure);
|
||||
if (_removed_interfaces != nullptr && obj->klass()->is_instance_klass() && obj->klass()->new_version() == nullptr) {
|
||||
do_compat_check_field_offsets(obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->klass()->new_version() != nullptr) {
|
||||
@@ -482,6 +595,7 @@ public:
|
||||
if (obj->size() - obj->size_given_klass(new_klass) != 0) {
|
||||
// We need an instance update => set back to old klass
|
||||
_needs_instance_update = true;
|
||||
_dcevm_shared_gc->update_fields_in_old(obj, new_klass->update_information());
|
||||
} else {
|
||||
// Either new size is bigger or gap is too small to be filled
|
||||
oop src = obj;
|
||||
@@ -492,7 +606,7 @@ public:
|
||||
src->set_klass(obj->klass()->new_version());
|
||||
// FIXME: instance updates...
|
||||
//guarantee(false, "instance updates!");
|
||||
DcevmSharedGC::update_fields(obj, src, new_klass->update_information());
|
||||
_dcevm_shared_gc->update_fields(obj, src, new_klass->update_information(), true);
|
||||
}
|
||||
} else {
|
||||
obj->set_klass(obj->klass()->new_version());
|
||||
@@ -505,14 +619,15 @@ class ChangePointersObjectTask : public WorkerTask {
|
||||
private:
|
||||
ChangePointersOopClosure<StoreBarrier>* _cl;
|
||||
ParallelObjectIterator* _poi;
|
||||
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
|
||||
bool _needs_instance_update;
|
||||
public:
|
||||
ChangePointersObjectTask(ChangePointersOopClosure<StoreBarrier>* cl, ParallelObjectIterator* poi) : WorkerTask("IterateObject Closure"),
|
||||
_cl(cl), _poi(poi), _needs_instance_update(false) { }
|
||||
ChangePointersObjectTask(ChangePointersOopClosure<StoreBarrier>* cl, ParallelObjectIterator* poi, VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces)
|
||||
: WorkerTask("IterateObject Closure"), _cl(cl), _poi(poi), _removed_interfaces(removed_interfaces), _needs_instance_update(false) { }
|
||||
|
||||
virtual void work(uint worker_id) {
|
||||
HandleMark hm(Thread::current()); // make sure any handles created are deleted
|
||||
ChangePointersObjectClosure objectClosure(_cl);
|
||||
ChangePointersObjectClosure objectClosure(_cl, _removed_interfaces);
|
||||
_poi->object_iterate(&objectClosure, worker_id);
|
||||
_needs_instance_update = _needs_instance_update || objectClosure.needs_instance_update();
|
||||
}
|
||||
@@ -521,6 +636,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ClearCompatCheckFields : public KlassClosure {
|
||||
public:
|
||||
ClearCompatCheckFields() {}
|
||||
void do_klass(Klass* k) {
|
||||
if (k->compat_check_field_offsets() != nullptr) {
|
||||
if (reinterpret_cast<intptr_t>(k->compat_check_field_offsets()) != -1) {
|
||||
delete k->compat_check_field_offsets();
|
||||
}
|
||||
k->clear_compat_check_field_offsets();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Main transformation method - runs in VM thread.
|
||||
// - for each scratch class call redefine_single_class
|
||||
// - clear code cache (flush_dependent_code)
|
||||
@@ -552,6 +680,7 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
}
|
||||
|
||||
Universe::set_inside_redefinition(true);
|
||||
DcevmSharedGC::create_static_instance();
|
||||
|
||||
// Mark methods seen on stack and everywhere else so old methods are not
|
||||
// cleaned up if they're on the stack.
|
||||
@@ -563,7 +692,10 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
Klass *new_class = _new_classes->at(i);
|
||||
new_class->old_version()->set_new_version(new_class);
|
||||
// MagicAccessorImpl new_class is set in load_new_class_versions
|
||||
if (new_class->old_version() != vmClasses::reflect_MagicAccessorImpl_klass() || new_class->old_version()->new_version() == nullptr) {
|
||||
new_class->old_version()->set_new_version(new_class);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
@@ -636,11 +768,11 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
WorkerThreads* workers = Universe::heap()->safepoint_workers();
|
||||
if (workers != nullptr && workers->active_workers() > 1) {
|
||||
ParallelObjectIterator poi(workers->active_workers());
|
||||
ChangePointersObjectTask objectTask(&oopClosure, &poi);
|
||||
ChangePointersObjectTask objectTask(&oopClosure, &poi, _removed_interfaces);
|
||||
workers->run_task(&objectTask);
|
||||
needs_instance_update = objectTask.needs_instance_update();
|
||||
} else {
|
||||
ChangePointersObjectClosure objectClosure(&oopClosure);
|
||||
ChangePointersObjectClosure objectClosure(&oopClosure, _removed_interfaces);
|
||||
Universe::heap()->object_iterate(&objectClosure);
|
||||
needs_instance_update = objectClosure.needs_instance_update();
|
||||
}
|
||||
@@ -676,7 +808,7 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
// Initialize the new class! Special static initialization that does not execute the
|
||||
// static constructor but copies static field values from the old class if name
|
||||
// and signature of a static field match.
|
||||
FieldCopier copier;
|
||||
FieldCopier copier(_removed_interfaces);
|
||||
cur->do_local_static_fields(&copier); // TODO (tw): What about internal static fields??
|
||||
//java_lang_Class::set_klass(old->java_mirror(), cur); // FIXME-isd (from JDK8): is that correct?
|
||||
//FIXME-isd (from JDK8): do we need this: ??? old->set_java_mirror(cur->java_mirror());
|
||||
@@ -750,6 +882,12 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
cur->clear_update_information();
|
||||
}
|
||||
|
||||
// delete compat_check_fields
|
||||
if (_removed_interfaces != nullptr) {
|
||||
ClearCompatCheckFields compat_check_fields;
|
||||
ClassLoaderDataGraph::classes_do(&compat_check_fields);
|
||||
}
|
||||
|
||||
// TODO: explain...
|
||||
LoaderConstraintTable::update_after_redefinition();
|
||||
|
||||
@@ -787,6 +925,7 @@ void VM_EnhancedRedefineClasses::doit() {
|
||||
}
|
||||
#endif
|
||||
|
||||
DcevmSharedGC::destroy_static_instance();
|
||||
Universe::set_inside_redefinition(false);
|
||||
_timer_vm_op_doit.stop();
|
||||
|
||||
@@ -878,9 +1017,10 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
|
||||
_max_redefinition_flags = Klass::NoRedefinition;
|
||||
|
||||
GrowableArray<Klass*>* prev_affected_klasses = new (mtInternal) GrowableArray<Klass*>(_class_count, mtInternal);
|
||||
GrowableArray<int> klass_redefinition_flags(_class_count, mtInternal);
|
||||
|
||||
do {
|
||||
err = load_new_class_versions_single_step(&old_2_new_klass_map, THREAD);
|
||||
err = load_new_class_versions_single_step(&old_2_new_klass_map, &klass_redefinition_flags, THREAD);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
delete prev_affected_klasses;
|
||||
return err;
|
||||
@@ -903,6 +1043,15 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
|
||||
delete _affected_klasses;
|
||||
_affected_klasses = prev_affected_klasses;
|
||||
|
||||
// Calculate instance update information after all new classes are resolved
|
||||
for (int i = 0; i < _new_classes->length(); i++) {
|
||||
int redefinition_flags = klass_redefinition_flags.at(i);
|
||||
if ((redefinition_flags & Klass::ModifyInstances) != 0) {
|
||||
Klass *new_class = _new_classes->at(i);
|
||||
calculate_instance_update_information(new_class);
|
||||
}
|
||||
}
|
||||
|
||||
// Link and verify new classes _after_ all classes have been updated in the system dictionary!
|
||||
for (int i = 0; i < _affected_klasses->length(); i++) {
|
||||
Klass* the_class = _affected_klasses->at(i);
|
||||
@@ -925,7 +1074,8 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions(TRAPS) {
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2NewKlassMap* old_2_new_klass_map, TRAPS) {
|
||||
jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2NewKlassMap* old_2_new_klass_map,
|
||||
GrowableArray<int>* klass_redefinition_flags, TRAPS) {
|
||||
|
||||
// thread local state - used to transfer class_being_redefined object to SystemDictonery::resolve_from_stream
|
||||
JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
|
||||
@@ -1101,6 +1251,14 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2N
|
||||
old_2_new_klass_map->put(the_class, new_class);
|
||||
_new_classes->append(new_class);
|
||||
|
||||
// If MagicAccessorImpl is being redefined, we must set new_version,
|
||||
// because class loading may trigger Reflection::verify_class_access,
|
||||
// which performs superclass checks. This can occur when a subclass
|
||||
// of MagicAccessorImpl is being loaded as part of the same redefinition run.
|
||||
if (the_class == vmClasses::reflect_MagicAccessorImpl_klass()) {
|
||||
the_class->set_new_version(new_class);
|
||||
}
|
||||
|
||||
if (the_class == vmClasses::Reference_klass()) {
|
||||
// must set offset+count to skip field "referent". Look at InstanceRefKlass::update_nonstatic_oop_maps
|
||||
OopMapBlock* old_map = the_class->start_of_nonstatic_oop_maps();
|
||||
@@ -1135,9 +1293,7 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2N
|
||||
|
||||
_max_redefinition_flags = _max_redefinition_flags | redefinition_flags;
|
||||
|
||||
if ((redefinition_flags & Klass::ModifyInstances) != 0) {
|
||||
calculate_instance_update_information(new_class);
|
||||
}
|
||||
klass_redefinition_flags->append(redefinition_flags);
|
||||
|
||||
if (the_class == vmClasses::Object_klass()) {
|
||||
_object_klass_redefined = true;
|
||||
@@ -1184,7 +1340,7 @@ int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_
|
||||
cur_klass = new_class->super();
|
||||
while (cur_klass != nullptr) {
|
||||
if (!the_class->is_subclass_of(cur_klass->is_redefining() ? cur_klass->old_version() : cur_klass)) {
|
||||
log_info(redefine, class, load)("added super class %s", cur_klass->name()->as_C_string());
|
||||
log_debug(redefine, class, load)("added super class %s", cur_klass->name()->as_C_string());
|
||||
result = result | Klass::ModifyClass | Klass::ModifyInstances;
|
||||
}
|
||||
cur_klass = cur_klass->super();
|
||||
@@ -1198,8 +1354,13 @@ int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_
|
||||
for (i = 0; i < old_interfaces->length(); i++) {
|
||||
InstanceKlass* old_interface = InstanceKlass::cast(old_interfaces->at(i));
|
||||
if (!new_class->implements_interface_dcevm(old_interface, old_2_new_klass_map)) {
|
||||
result = result | Klass::RemoveSuperType | Klass::ModifyClass;
|
||||
log_info(redefine, class, load)("removed interface %s", old_interface->name()->as_C_string());
|
||||
result = result | Klass::RemoveInterface | Klass::ModifyClass;
|
||||
log_debug(redefine, class, load)("removed interface %s", old_interface->name()->as_C_string());
|
||||
if (_removed_interfaces == nullptr) {
|
||||
_removed_interfaces = new (mtInternal) SymbolSet();
|
||||
}
|
||||
Symbol* interf_sign_sym = SymbolTable::new_symbol(old_interface->signature_name());
|
||||
_removed_interfaces->put(interf_sign_sym, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,7 +1369,7 @@ int VM_EnhancedRedefineClasses::calculate_redefinition_flags(InstanceKlass* new_
|
||||
for (i = 0; i<new_interfaces->length(); i++) {
|
||||
if (!the_class->implements_interface_dcevm(new_interfaces->at(i), old_2_new_klass_map)) {
|
||||
result = result | Klass::ModifyClass;
|
||||
log_info(redefine, class, load)("added interface %s", new_interfaces->at(i)->name()->as_C_string());
|
||||
log_debug(redefine, class, load)("added interface %s", new_interfaces->at(i)->name()->as_C_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1484,7 +1645,7 @@ jvmtiError VM_EnhancedRedefineClasses::find_class_bytes(InstanceKlass* the_class
|
||||
|
||||
// Calculate difference between non static fields of old and new class and store the info into new class:
|
||||
// instanceKlass->store_update_information
|
||||
// instanceKlass->copy_backwards
|
||||
// instanceKlass->copying_backwards
|
||||
void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* new_version) {
|
||||
|
||||
class CalculateFieldUpdates : public FieldClosure {
|
||||
@@ -1492,17 +1653,24 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
|
||||
private:
|
||||
InstanceKlass* _old_ik;
|
||||
GrowableArray<int> _update_info;
|
||||
VM_EnhancedRedefineClasses::SymbolSet* _removed_interfaces;
|
||||
int _position;
|
||||
bool _copy_backwards;
|
||||
bool _copying_backwards;
|
||||
bool _compat_check;
|
||||
|
||||
public:
|
||||
|
||||
bool does_copy_backwards() {
|
||||
return _copy_backwards;
|
||||
bool is_copying_backwards() {
|
||||
return _copying_backwards;
|
||||
}
|
||||
|
||||
CalculateFieldUpdates(InstanceKlass* old_ik) :
|
||||
_old_ik(old_ik), _position(instanceOopDesc::base_offset_in_bytes()), _copy_backwards(false) {
|
||||
bool is_compat_check() {
|
||||
return _compat_check;
|
||||
}
|
||||
|
||||
CalculateFieldUpdates(InstanceKlass* old_ik, VM_EnhancedRedefineClasses::SymbolSet* removed_interfaces) :
|
||||
_old_ik(old_ik), _removed_interfaces(removed_interfaces), _position(instanceOopDesc::base_offset_in_bytes()),
|
||||
_copying_backwards(false), _compat_check() {
|
||||
_update_info.append(_position);
|
||||
_update_info.append(0);
|
||||
}
|
||||
@@ -1524,43 +1692,78 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
|
||||
assert(_position == fd->offset(), "must be correct offset!");
|
||||
|
||||
InstanceKlass* holder = fd->field_holder();
|
||||
InstanceKlass* maybe_old_holder = holder->is_redefining() ? InstanceKlass::cast(holder->old_version()) : holder;
|
||||
if (fd->index() < holder->java_fields_count()) {
|
||||
fieldDescriptor old_fd;
|
||||
if (_old_ik->find_field(fd->name(), fd->signature(), false, &old_fd) != nullptr) {
|
||||
// Found field in the old class, copy
|
||||
copy(old_fd.offset(), type2aelembytes(fd->field_type()));
|
||||
|
||||
if (old_fd.offset() < fd->offset()) {
|
||||
_copy_backwards = true;
|
||||
bool found = false;
|
||||
if (_old_ik->find_field(fd->name(), fd->signature(), false, &old_fd) != nullptr) {
|
||||
found = true;
|
||||
} else {
|
||||
if (maybe_old_holder->find_local_field_by_name(fd->name(), &old_fd) && !old_fd.is_static()) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
// Found field in the old class, copy
|
||||
Symbol *sig_new = fd->signature();
|
||||
Symbol *sig_old = old_fd.signature();
|
||||
int compat_flag;
|
||||
|
||||
if (sig_new == sig_old) {
|
||||
if (_removed_interfaces != nullptr && _removed_interfaces->contains(sig_old) && fd->field_type() == T_OBJECT && old_fd.field_type() == T_OBJECT) {
|
||||
compat_flag = 0;
|
||||
_compat_check = true;
|
||||
} else {
|
||||
compat_flag = 1;
|
||||
}
|
||||
} else {
|
||||
if (fd->field_type() == T_OBJECT && old_fd.field_type() == T_OBJECT) {
|
||||
compat_flag = 0;
|
||||
_compat_check = true;
|
||||
} else {
|
||||
compat_flag = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer special flags
|
||||
fd->set_is_field_modification_watched(old_fd.is_field_modification_watched());
|
||||
fd->set_is_field_access_watched(old_fd.is_field_access_watched());
|
||||
if (compat_flag != -1) {
|
||||
copy(old_fd.offset(), type2aelembytes(fd->field_type()), (compat_flag == 0));
|
||||
|
||||
if (old_fd.offset() < fd->offset()) {
|
||||
_copying_backwards = true;
|
||||
}
|
||||
|
||||
// Transfer special flags
|
||||
fd->set_is_field_modification_watched(old_fd.is_field_modification_watched());
|
||||
fd->set_is_field_access_watched(old_fd.is_field_access_watched());
|
||||
} else {
|
||||
fill(type2aelembytes(fd->field_type()));
|
||||
}
|
||||
} else {
|
||||
// New field, fill
|
||||
fill(type2aelembytes(fd->field_type()));
|
||||
}
|
||||
} else {
|
||||
FieldInfo internal_field = holder->field(fd->index());
|
||||
InstanceKlass* maybe_old_klass = holder->is_redefining() ? InstanceKlass::cast(holder->old_version()) : holder;
|
||||
int java_fields_count = maybe_old_klass->java_fields_count();
|
||||
|
||||
int java_fields_count = maybe_old_holder->java_fields_count();
|
||||
int num_injected;
|
||||
const InjectedField* const injected = JavaClasses::get_injected(maybe_old_klass->name(), &num_injected);
|
||||
for (int i = java_fields_count; i < java_fields_count+num_injected; i++) {
|
||||
FieldInfo maybe_old_field = maybe_old_klass->field(i);
|
||||
const InjectedField *const injected = JavaClasses::get_injected(maybe_old_holder->name(), &num_injected);
|
||||
for (int i = java_fields_count; i < java_fields_count + num_injected; i++) {
|
||||
FieldInfo maybe_old_field = maybe_old_holder->field(i);
|
||||
if (maybe_old_field.field_flags().is_injected() &&
|
||||
internal_field.field_flags().is_injected() &&
|
||||
maybe_old_field.lookup_symbol(maybe_old_field.name_index()) == internal_field.lookup_symbol(internal_field.name_index())) {
|
||||
copy(maybe_old_field.offset(), type2aelembytes(Signature::basic_type(internal_field.signature_injected_dcevm())));
|
||||
copy(maybe_old_field.offset(), type2aelembytes(Signature::basic_type(internal_field.signature_injected_dcevm())), false);
|
||||
if (maybe_old_field.offset() < internal_field.offset()) {
|
||||
_copy_backwards = true;
|
||||
_copying_backwards = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void fill(int size) {
|
||||
@@ -1572,19 +1775,24 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
|
||||
_position += size;
|
||||
}
|
||||
|
||||
void copy(int offset, int size) {
|
||||
int prev_end = -1;
|
||||
if (_update_info.length() > 0 && _update_info.at(_update_info.length() - 1) > 0) {
|
||||
prev_end = _update_info.at(_update_info.length() - 2) + _update_info.at(_update_info.length() - 1);
|
||||
}
|
||||
void copy(int offset, int size, bool needs_compat_check) {
|
||||
if (!needs_compat_check && _update_info.length() >= 2) {
|
||||
int last_size = _update_info.at(_update_info.length() - 2);
|
||||
int last_offset = _update_info.at(_update_info.length() - 1);
|
||||
|
||||
if (prev_end == offset) {
|
||||
(*_update_info.adr_at(_update_info.length() - 2)) += size;
|
||||
} else {
|
||||
_update_info.append(size);
|
||||
_update_info.append(offset);
|
||||
if (last_offset > 0 && (last_size & DcevmSharedGC::UpdateInfoCompatFlag) == 0) {
|
||||
int last_len = last_size & DcevmSharedGC::UpdateInfoLengthMask;
|
||||
int prev_end = last_offset + last_len;
|
||||
if (prev_end == offset) {
|
||||
(*_update_info.adr_at(_update_info.length() - 2)) += size;
|
||||
_position += size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int tagged_size = needs_compat_check ? (size | DcevmSharedGC::UpdateInfoCompatFlag) : size;
|
||||
_update_info.append(tagged_size);
|
||||
_update_info.append(offset);
|
||||
_position += size;
|
||||
}
|
||||
};
|
||||
@@ -1593,15 +1801,16 @@ void VM_EnhancedRedefineClasses::calculate_instance_update_information(Klass* ne
|
||||
InstanceKlass* old_ik = InstanceKlass::cast(new_version->old_version());
|
||||
|
||||
//
|
||||
CalculateFieldUpdates cl(old_ik);
|
||||
CalculateFieldUpdates cl(old_ik, _removed_interfaces);
|
||||
ik->do_nonstatic_fields_dcevm(&cl);
|
||||
|
||||
GrowableArray<int> result = cl.finish();
|
||||
ik->store_update_information(result);
|
||||
ik->set_copying_backwards(cl.does_copy_backwards());
|
||||
ik->set_copying_backwards(cl.is_copying_backwards());
|
||||
|
||||
if (log_is_enabled(Trace, redefine, class, obsolete, metadata)) {
|
||||
log_trace(redefine, class, obsolete, metadata)("Instance update information for %s:", new_version->name()->as_C_string());
|
||||
if (cl.does_copy_backwards()) {
|
||||
if (cl.is_copying_backwards()) {
|
||||
log_trace(redefine, class, obsolete, metadata)("\tDoes copy backwards!");
|
||||
}
|
||||
for (int i=0; i<result.length(); i++) {
|
||||
@@ -1766,21 +1975,24 @@ u8 VM_EnhancedRedefineClasses::next_id() {
|
||||
}
|
||||
|
||||
// Clean method data for this class
|
||||
void VM_EnhancedRedefineClasses::MethodDataCleaner::do_klass(Klass* k) {
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass *ik = InstanceKlass::cast(k);
|
||||
// Clean MethodData of this class's methods so they don't refer to
|
||||
// old methods that are no longer running.
|
||||
Array<Method*>* methods = ik->methods();
|
||||
int num_methods = methods->length();
|
||||
for (int index = 0; index < num_methods; ++index) {
|
||||
if (methods->at(index)->method_data() != nullptr) {
|
||||
methods->at(index)->method_data()->clean_weak_method_links();
|
||||
class MethodDataCleaner : public KlassClosure {
|
||||
public:
|
||||
MethodDataCleaner() {}
|
||||
void do_klass(Klass* k) {
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass *ik = InstanceKlass::cast(k);
|
||||
// Clean MethodData of this class's methods so they don't refer to
|
||||
// old methods that are no longer running.
|
||||
Array<Method*>* methods = ik->methods();
|
||||
int num_methods = methods->length();
|
||||
for (int index = 0; index < num_methods; ++index) {
|
||||
if (methods->at(index)->method_data() != nullptr) {
|
||||
methods->at(index)->method_data()->clean_weak_method_links();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void VM_EnhancedRedefineClasses::update_jmethod_ids(Thread *current) {
|
||||
for (int j = 0; j < _matching_methods_length; ++j) {
|
||||
@@ -2343,7 +2555,7 @@ jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(bool do_init
|
||||
log_trace(redefine, class, load)("%s", _affected_klasses->at(i)->name()->as_C_string());
|
||||
}
|
||||
}
|
||||
return JVMTI_ERROR_NONE;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pairs of class dependencies (for topological sort)
|
||||
@@ -2389,6 +2601,18 @@ jvmtiError VM_EnhancedRedefineClasses::do_topological_class_sorting(Old2NewKlass
|
||||
old_2_new_klass_map,
|
||||
THREAD);
|
||||
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
|
||||
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
|
||||
if (message != nullptr) {
|
||||
char* ex_msg = java_lang_String::as_utf8_string(message);
|
||||
log_info(redefine, class, load, exceptions)("parse_class exception: '%s %s'", ex_name->as_C_string(), ex_msg);
|
||||
} else {
|
||||
log_info(redefine, class, load, exceptions)("parse_class exception: '%s'", ex_name->as_C_string());
|
||||
}
|
||||
return JVMTI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
const Klass* super_klass = parser.super_klass();
|
||||
if (super_klass != nullptr && _affected_klasses->contains((Klass*) super_klass)) {
|
||||
links.append(KlassPair(super_klass, klass));
|
||||
|
||||
@@ -47,7 +47,11 @@
|
||||
// - doit() - main redefition, adjust existing objects on the heap, clear caches
|
||||
// - doit_epilogue() - cleanup
|
||||
class VM_EnhancedRedefineClasses: public VM_GC_Operation {
|
||||
private:
|
||||
public:
|
||||
static unsigned int sym_hash (Symbol* const& s) { return (int)(uintptr_t)s; }
|
||||
static bool sym_equals(Symbol* const& a, Symbol* const& b) { return a == b; }
|
||||
typedef ResourceHashtable<Symbol*, char, 37, AnyObj::C_HEAP, mtInternal, &sym_hash, &sym_equals> SymbolSet;
|
||||
private:
|
||||
// These static fields are needed by ClassLoaderDataGraph::classes_do()
|
||||
// facility and the AdjustCpoolCacheAndVtable helper:
|
||||
static Array<Method*>* _old_methods;
|
||||
@@ -71,7 +75,7 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
|
||||
// RetransformClasses. Indicate which.
|
||||
JvmtiClassLoadKind _class_load_kind;
|
||||
|
||||
GrowableArray<InstanceKlass*>* _new_classes;
|
||||
GrowableArray<InstanceKlass*>* _new_classes;
|
||||
jvmtiError _res;
|
||||
|
||||
// Set if any of the InstanceKlasses have entries in the ResolvedMethodTable
|
||||
@@ -90,6 +94,8 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
|
||||
|
||||
int _max_redefinition_flags;
|
||||
|
||||
SymbolSet* _removed_interfaces;
|
||||
|
||||
// Performance measurement support. These timers do not cover all
|
||||
// the work done for JVM/TI RedefineClasses() but they do cover
|
||||
// the heavy lifting.
|
||||
@@ -113,7 +119,7 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
|
||||
//
|
||||
// The result is sotred in _affected_klasses(old definitions) and _new_classes(new definitions) arrays.
|
||||
jvmtiError load_new_class_versions(TRAPS);
|
||||
jvmtiError load_new_class_versions_single_step(Old2NewKlassMap* old_2_new_klass_map, TRAPS);
|
||||
jvmtiError load_new_class_versions_single_step(Old2NewKlassMap* old_2_new_klass_map, GrowableArray<int>* klass_redefinition_flags, TRAPS);
|
||||
|
||||
// Searches for all affected classes and performs a sorting such tha
|
||||
// a supertype is always before a subtype.
|
||||
@@ -171,13 +177,6 @@ class VM_EnhancedRedefineClasses: public VM_GC_Operation {
|
||||
ClearCpoolCacheAndUnpatch(Thread* t) : _thread(t) {}
|
||||
void do_klass(Klass* k);
|
||||
};
|
||||
|
||||
// Clean MethodData out
|
||||
class MethodDataCleaner : public KlassClosure {
|
||||
public:
|
||||
MethodDataCleaner() {}
|
||||
void do_klass(Klass* k);
|
||||
};
|
||||
public:
|
||||
VM_EnhancedRedefineClasses(jint class_count,
|
||||
const jvmtiClassDefinition *class_defs,
|
||||
|
||||
@@ -64,6 +64,9 @@ class WindowsPath implements Path {
|
||||
// paths and has a long path prefix for all paths longer than MAX_PATH.
|
||||
private volatile WeakReference<String> pathForWin32Calls;
|
||||
|
||||
// Used for fast string comparison.
|
||||
private volatile WeakReference<byte[]> uppercasePath;
|
||||
|
||||
// offsets into name components (computed lazily)
|
||||
private volatile Integer[] offsets;
|
||||
|
||||
@@ -791,23 +794,7 @@ class WindowsPath implements Path {
|
||||
public int compareTo(Path obj) {
|
||||
if (obj == null)
|
||||
throw new NullPointerException();
|
||||
String s1 = path;
|
||||
String s2 = ((WindowsPath)obj).path;
|
||||
int n1 = s1.length();
|
||||
int n2 = s2.length();
|
||||
int min = Math.min(n1, n2);
|
||||
for (int i = 0; i < min; i++) {
|
||||
char c1 = s1.charAt(i);
|
||||
char c2 = s2.charAt(i);
|
||||
if (c1 != c2) {
|
||||
c1 = Character.toUpperCase(c1);
|
||||
c2 = Character.toUpperCase(c2);
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return n1 - n2;
|
||||
return Arrays.compareUnsigned(getUppercasePath(), ((WindowsPath)obj).getUppercasePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -917,6 +904,15 @@ class WindowsPath implements Path {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getUppercasePath() {
|
||||
byte[] result = uppercasePath != null ? uppercasePath.get() : null;
|
||||
if (result == null) {
|
||||
result = path.toUpperCase().getBytes();
|
||||
uppercasePath = new WeakReference<>(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI toUri() {
|
||||
return WindowsUriSupport.toUri(this);
|
||||
|
||||
@@ -67,6 +67,7 @@ import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
@@ -1096,4 +1097,23 @@ class CAccessibility implements PropertyChangeListener {
|
||||
}
|
||||
}, c, false);
|
||||
}
|
||||
|
||||
private static Accessible getScrollBar(Accessible a, Component c, int orientation) {
|
||||
if (a == null) return null;
|
||||
|
||||
return invokeAndWait(() -> {
|
||||
Accessible sa = CAccessible.getSwingAccessible(a);
|
||||
if (sa instanceof JScrollPane scrollPane) {
|
||||
// NSAccessibilityOrientationVertical
|
||||
if (orientation == 1) {
|
||||
return scrollPane.getVerticalScrollBar();
|
||||
}
|
||||
// NSAccessibilityOrientationHorizontal
|
||||
else if (orientation == 2) {
|
||||
return scrollPane.getHorizontalScrollBar();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +405,8 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
AccessibleRole thisRole = accessible.getAccessibleContext()
|
||||
.getAccessibleRole();
|
||||
if (thisRole == AccessibleRole.SLIDER ||
|
||||
thisRole == AccessibleRole.PROGRESS_BAR) {
|
||||
thisRole == AccessibleRole.PROGRESS_BAR ||
|
||||
thisRole == AccessibleRole.SCROLL_BAR) {
|
||||
execute(ptr -> valueChanged(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +244,13 @@ public class CDataTransferer extends DataTransferer {
|
||||
|
||||
@Override
|
||||
protected byte[] imageToPlatformBytes(Image image, long format) {
|
||||
String formatString = getNativeForFormat(format);
|
||||
byte[] result = CImage.getCreator().getPlatformImageBytesForFormat(image, formatString);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// fallback
|
||||
return CImage.getCreator().getPlatformImageBytes(image);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,12 @@
|
||||
package sun.lwawt.macosx;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.geom.Dimension2D;
|
||||
import java.awt.image.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.awt.image.MultiResolutionImage;
|
||||
@@ -38,6 +41,8 @@ import sun.awt.image.MultiResolutionCachedImage;
|
||||
|
||||
import sun.awt.image.SunWritableRaster;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class CImage extends CFRetainedResource {
|
||||
private static native long nativeCreateNSImageFromArray(int[] buffer, int w, int h);
|
||||
private static native long nativeCreateNSImageFromBytes(byte[] buffer);
|
||||
@@ -176,6 +181,41 @@ public class CImage extends CFRetainedResource {
|
||||
return nativeGetPlatformImageBytes(buffer, image.getWidth(null), image.getHeight(null));
|
||||
}
|
||||
|
||||
public byte[] getPlatformImageBytesForFormat(final Image image, final String format) {
|
||||
if (format.equals("TIFF")) {
|
||||
return getPlatformImageBytes(image);
|
||||
}
|
||||
|
||||
BufferedImage bufferedImage;
|
||||
|
||||
if (image instanceof BufferedImage) {
|
||||
bufferedImage = (BufferedImage) image;
|
||||
} else {
|
||||
int width = image.getWidth(null);
|
||||
int height = image.getHeight(null);
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = bufferedImage.createGraphics();
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (!ImageIO.write(bufferedImage, format, out)) {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a byte array which contains platform-specific image data in the given format into an Image.
|
||||
*/
|
||||
|
||||
@@ -179,6 +179,26 @@ enum ShortcutID {
|
||||
Shortcut_ToggleSpeakSelection = 230,
|
||||
Shortcut_ToggleSpeakItemUnderPointer = 231,
|
||||
Shortcut_ToggleTypingFeedback = 232,
|
||||
Shortcut_MinimizeWindow = 233,
|
||||
Shortcut_ZoomWindow = 235,
|
||||
Shortcut_FillWindow = 237,
|
||||
Shortcut_CenterWindow = 238,
|
||||
Shortcut_RestoreWindow = 239,
|
||||
Shortcut_TileLeftHalf = 240,
|
||||
Shortcut_TileRightHalf = 241,
|
||||
Shortcut_TileTopHalf = 242,
|
||||
Shortcut_TileBottomHalf = 243,
|
||||
Shortcut_TileTopLeftQuarter = 244,
|
||||
Shortcut_TileTopRightQuarter = 245,
|
||||
Shortcut_TileBottomLeftQuarter = 246,
|
||||
Shortcut_TileBottomRightQuarter = 247,
|
||||
Shortcut_ArrangeLeftRight = 248,
|
||||
Shortcut_ArrangeRightLeft = 249,
|
||||
Shortcut_ArrangeTopBottom = 250,
|
||||
Shortcut_ArrangeBottomTop = 251,
|
||||
Shortcut_ArrangeQuarters = 256,
|
||||
Shortcut_FullScreenTileLeft = 257,
|
||||
Shortcut_FullScreenTileRight = 258,
|
||||
};
|
||||
|
||||
struct SymbolicHotKey {
|
||||
@@ -204,67 +224,88 @@ struct SymbolicHotKey {
|
||||
// Modifier mask using the NSEventModifierFlag* values for this shortcut
|
||||
int modifiers;
|
||||
|
||||
// The first major version of macOS that has this shortcut or -1 if unknown.
|
||||
int macOSVersion;
|
||||
// The first version of macOS that has this shortcut or -1 if unknown.
|
||||
int macOSVersionMajor;
|
||||
int macOSVersionMinor;
|
||||
};
|
||||
|
||||
static const struct SymbolicHotKey defaultSymbolicHotKeys[] = {
|
||||
[Shortcut_FocusMenuBar] = { "FocusMenuBar", "Move focus to the menu bar", YES, 65535, 120, 0x00840000, -1 },
|
||||
[Shortcut_FocusDock] = { "FocusDock", "Move focus to the Dock", YES, 65535, 99, 0x00840000, -1 },
|
||||
[Shortcut_FocusActiveWindow] = { "FocusActiveWindow", "Move focus to active or next window", YES, 65535, 118, 0x00840000, -1 },
|
||||
[Shortcut_FocusToolbar] = { "FocusToolbar", "Move focus to window toolbar", YES, 65535, 96, 0x00840000, -1 },
|
||||
[Shortcut_FocusFloatingWindow] = { "FocusFloatingWindow", "Move focus to floating window", YES, 65535, 97, 0x00840000, -1 },
|
||||
[Shortcut_ToggleKeyboardAccess] = { "ToggleKeyboardAccess", "Turn keyboard access on or off", YES, 65535, 122, 0x00840000, -1 },
|
||||
[Shortcut_ChangeTabMode] = { "ChangeTabMode", "Change the way Tab moves focus", YES, 65535, 98, 0x00840000, -1 },
|
||||
[Shortcut_ToggleZoom] = { "ToggleZoom", "Zoom: Turn zoom on or off", NO, 56, 28, 0x00180000, -1 },
|
||||
[Shortcut_ZoomIn] = { "ZoomIn", "Zoom: Zoom in", NO, 61, 24, 0x00180000, -1 },
|
||||
[Shortcut_ZoomOut] = { "ZoomOut", "Zoom: Zoom out", NO, 45, 27, 0x00180000, -1 },
|
||||
[Shortcut_InvertColors] = { "InvertColors", "Invert colors", YES, 56, 28, 0x001c0000, -1 },
|
||||
[Shortcut_ToggleZoomImageSmoothing] = { "ToggleZoomImageSmoothing", "Zoom: Turn image smoothing on or off", NO, 92, 42, 0x00180000, -1 },
|
||||
[Shortcut_IncreaseContrast] = { "IncreaseContrast", "Increase contrast", NO, 46, 47, 0x001c0000, -1 },
|
||||
[Shortcut_DecreaseContrast] = { "DecreaseContrast", "Decrease contrast", NO, 44, 43, 0x001c0000, -1 },
|
||||
[Shortcut_FocusNextApplicationWindow] = { "FocusNextApplicationWindow", "Move focus to the next window in application", YES, 96, 50, 0x00100000, -1 },
|
||||
[Shortcut_ScreenshotToFile] = { "ScreenshotToFile", "Save picture of screen as a file", YES, 51, 20, 0x00120000, -1 },
|
||||
[Shortcut_ScreenshotToClipboard] = { "ScreenshotToClipboard", "Copy picture of screen to the clipboard", YES, 51, 20, 0x00160000, -1 },
|
||||
[Shortcut_ScreenshotAreaToFile] = { "ScreenshotAreaToFile", "Save picture of selected area as a file", YES, 52, 21, 0x00120000, -1 },
|
||||
[Shortcut_ScreenshotAreaToClipboard] = { "ScreenshotAreaToClipboard", "Copy picture of selected area to the clipboard", YES, 52, 21, 0x00160000, -1 },
|
||||
[Shortcut_ShowAllWindows] = { "ShowAllWindows", "Mission Control", YES, 65535, 126, 0x00840000, -1 },
|
||||
[Shortcut_ShowApplicationWindows] = { "ShowApplicationWindows", "Application windows", YES, 65535, 125, 0x00840000, -1 },
|
||||
[Shortcut_ShowDesktop] = { "ShowDesktop", "Show desktop", YES, 65535, 103, 0x00800000, -1 },
|
||||
[Shortcut_ToggleDockHiding] = { "ToggleDockHiding", "Turn Dock hiding on/off", YES, 100, 2, 0x00180000, -1 },
|
||||
[Shortcut_DecreaseBrightness] = { "DecreaseBrightness", "Decrease display brightness", YES, 65535, 107, 0x00800000, -1 },
|
||||
[Shortcut_IncreaseBrightness] = { "IncreaseBrightness", "Increase display brightness", YES, 65535, 113, 0x00800000, -1 },
|
||||
[Shortcut_FocusStatusMenu] = { "FocusStatusMenu", "Move focus to the status menus", YES, 65535, 100, 0x00840000, -1 },
|
||||
[Shortcut_ToggleVoiceOver] = { "ToggleVoiceOver", "Turn VoiceOver on or off", YES, 65535, 96, 0x00900000, -1 },
|
||||
[Shortcut_SelectPreviousInputSource] = { "SelectPreviousInputSource", "Select the previous input source", YES, 32, 49, 0x00040000, -1 },
|
||||
[Shortcut_SelectNextInputSource] = { "SelectNextInputSource", "Select next source in Input menu", YES, 32, 49, 0x000c0000, -1 },
|
||||
[Shortcut_ShowSpotlight] = { "ShowSpotlight", "Show Spotlight Search", YES, 32, 49, 0x00100000, -1 },
|
||||
[Shortcut_ShowFinderSearch] = { "ShowFinderSearch", "Show Finder search window", YES, 32, 49, 0x00180000, -1 },
|
||||
[Shortcut_SwitchToDesktopLeft] = { "SwitchToDesktopLeft", "Move left a space", NO, 65535, 123, 0x00840000, -1 },
|
||||
[Shortcut_SwitchToDesktopRight] = { "SwitchToDesktopRight", "Move right a space", NO, 65535, 124, 0x00840000, -1 },
|
||||
[Shortcut_SwitchToDesktop1] = { "SwitchToDesktop1", "Switch to Desktop 1", NO, 65535, 18, 0x00040000, -1 },
|
||||
[Shortcut_SwitchToDesktop2] = { "SwitchToDesktop2", "Switch to Desktop 2", NO, 65535, 19, 0x00040000, -1 },
|
||||
[Shortcut_SwitchToDesktop3] = { "SwitchToDesktop3", "Switch to Desktop 3", NO, 65535, 20, 0x00040000, -1 },
|
||||
[Shortcut_SwitchToDesktop4] = { "SwitchToDesktop4", "Switch to Desktop 4", NO, 65535, 21, 0x00040000, -1 },
|
||||
[Shortcut_ShowContextualMenu] = { "ShowContextualMenu", "Show contextual menu", YES, 65535, 36, 0x00040000, 15 },
|
||||
[Shortcut_ShowLaunchpad] = { "ShowLaunchpad", "Show Launchpad", NO, 65535, 65535, 0, -1 },
|
||||
[Shortcut_ShowAccessibilityControls] = { "ShowAccessibilityControls", "Show Accessibility controls", YES, 65535, 96, 0x00980000, -1 },
|
||||
[Shortcut_ShowNotificationCenter] = { "ShowNotificationCenter", "Show Notification Center", NO, 65535, 65535, 0, -1 },
|
||||
[Shortcut_ToggleDoNotDisturb] = { "ToggleDoNotDisturb", "Turn Do Not Disturb on/off", YES, 65535, 65535, 0, -1 },
|
||||
[Shortcut_ToggleZoomFocusFollowing] = { "ToggleZoomFocusFollowing", "Zoom: Turn focus following on or off", NO, 65535, 65535, 0, -1 },
|
||||
[Shortcut_ScreenshotOptions] = { "ScreenshotOptions", "Screenshot and recording options", YES, 53, 23, 0x00120000, -1 },
|
||||
[Shortcut_OpenQuickNote] = { "OpenQuickNote", "Quick note", YES, 113, 12, 0x00800000, -1 },
|
||||
[Shortcut_ToggleStageManager] = { "ToggleStageManager", "Turn Stage Manager on/off", NO, 65535, 65535, 0, -1 },
|
||||
[Shortcut_TogglePresenterOverlayLarge] = { "TogglePresenterOverlayLarge", "Turn Presenter Overlay (large) on or off", YES, 65535, 65535, 0, -1 },
|
||||
[Shortcut_TogglePresenterOverlaySmall] = { "TogglePresenterOverlaySmall", "Turn Presenter Overlay (small) on or off", YES, 65535, 65535, 0, -1 },
|
||||
[Shortcut_ToggleLiveSpeech] = { "ToggleLiveSpeech", "LiveSpeech: Turn Live Speech on or off", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_ToggleLiveSpeechVisibility] = { "ToggleLiveSpeechVisibility", "LiveSpeech: Toggle visibility", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_PauseOrResumeLiveSpeech] = { "PauseOrResumeLiveSpeech", "LiveSpeech: Pause or resume speech", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_CancelLiveSpeech] = { "CancelLiveSpeech", "LiveSpeech: Cancel speech", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_ToggleLiveSpeechPhrases] = { "ToggleLiveSpeechPhrases", "LiveSpeech: Hide or show phrases", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_ToggleSpeakSelection] = { "ToggleSpeakSelection", "Turn speak selection on or off", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_ToggleSpeakItemUnderPointer] = { "ToggleSpeakItemUnderPointer", "Turn speak item under the pointer on or off", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_ToggleTypingFeedback] = { "ToggleTypingFeedback", "Turn typing feedback on or off", YES, 65535, 65535, 0, 14 },
|
||||
[Shortcut_FocusMenuBar] = { "FocusMenuBar", "Move focus to the menu bar", YES, 65535, 120, 0x00840000, -1, -1 },
|
||||
[Shortcut_FocusDock] = { "FocusDock", "Move focus to the Dock", YES, 65535, 99, 0x00840000, -1, -1 },
|
||||
[Shortcut_FocusActiveWindow] = { "FocusActiveWindow", "Move focus to active or next window", YES, 65535, 118, 0x00840000, -1, -1 },
|
||||
[Shortcut_FocusToolbar] = { "FocusToolbar", "Move focus to window toolbar", YES, 65535, 96, 0x00840000, -1, -1 },
|
||||
[Shortcut_FocusFloatingWindow] = { "FocusFloatingWindow", "Move focus to floating window", YES, 65535, 97, 0x00840000, -1, -1 },
|
||||
[Shortcut_ToggleKeyboardAccess] = { "ToggleKeyboardAccess", "Turn keyboard access on or off", YES, 65535, 122, 0x00840000, -1, -1 },
|
||||
[Shortcut_ChangeTabMode] = { "ChangeTabMode", "Change the way Tab moves focus", YES, 65535, 98, 0x00840000, -1, -1 },
|
||||
[Shortcut_ToggleZoom] = { "ToggleZoom", "Zoom: Turn zoom on or off", NO, 56, 28, 0x00180000, -1, -1 },
|
||||
[Shortcut_ZoomIn] = { "ZoomIn", "Zoom: Zoom in", NO, 61, 24, 0x00180000, -1, -1 },
|
||||
[Shortcut_ZoomOut] = { "ZoomOut", "Zoom: Zoom out", NO, 45, 27, 0x00180000, -1, -1 },
|
||||
[Shortcut_InvertColors] = { "InvertColors", "Invert colors", YES, 56, 28, 0x001c0000, -1, -1 },
|
||||
[Shortcut_ToggleZoomImageSmoothing] = { "ToggleZoomImageSmoothing", "Zoom: Turn image smoothing on or off", NO, 92, 42, 0x00180000, -1, -1 },
|
||||
[Shortcut_IncreaseContrast] = { "IncreaseContrast", "Increase contrast", NO, 46, 47, 0x001c0000, -1, -1 },
|
||||
[Shortcut_DecreaseContrast] = { "DecreaseContrast", "Decrease contrast", NO, 44, 43, 0x001c0000, -1, -1 },
|
||||
[Shortcut_FocusNextApplicationWindow] = { "FocusNextApplicationWindow", "Move focus to the next window in application", YES, 96, 50, 0x00100000, -1, -1 },
|
||||
[Shortcut_ScreenshotToFile] = { "ScreenshotToFile", "Save picture of screen as a file", YES, 51, 20, 0x00120000, -1, -1 },
|
||||
[Shortcut_ScreenshotToClipboard] = { "ScreenshotToClipboard", "Copy picture of screen to the clipboard", YES, 51, 20, 0x00160000, -1, -1 },
|
||||
[Shortcut_ScreenshotAreaToFile] = { "ScreenshotAreaToFile", "Save picture of selected area as a file", YES, 52, 21, 0x00120000, -1, -1 },
|
||||
[Shortcut_ScreenshotAreaToClipboard] = { "ScreenshotAreaToClipboard", "Copy picture of selected area to the clipboard", YES, 52, 21, 0x00160000, -1, -1 },
|
||||
[Shortcut_ShowAllWindows] = { "ShowAllWindows", "Mission Control", YES, 65535, 126, 0x00840000, -1, -1 },
|
||||
[Shortcut_ShowApplicationWindows] = { "ShowApplicationWindows", "Application windows", YES, 65535, 125, 0x00840000, -1, -1 },
|
||||
[Shortcut_ShowDesktop] = { "ShowDesktop", "Show desktop", YES, 65535, 103, 0x00800000, -1, -1 },
|
||||
[Shortcut_ToggleDockHiding] = { "ToggleDockHiding", "Turn Dock hiding on/off", YES, 100, 2, 0x00180000, -1, -1 },
|
||||
[Shortcut_DecreaseBrightness] = { "DecreaseBrightness", "Decrease display brightness", YES, 65535, 107, 0x00800000, -1, -1 },
|
||||
[Shortcut_IncreaseBrightness] = { "IncreaseBrightness", "Increase display brightness", YES, 65535, 113, 0x00800000, -1, -1 },
|
||||
[Shortcut_FocusStatusMenu] = { "FocusStatusMenu", "Move focus to the status menus", YES, 65535, 100, 0x00840000, -1, -1 },
|
||||
[Shortcut_ToggleVoiceOver] = { "ToggleVoiceOver", "Turn VoiceOver on or off", YES, 65535, 96, 0x00900000, -1, -1 },
|
||||
[Shortcut_SelectPreviousInputSource] = { "SelectPreviousInputSource", "Select the previous input source", YES, 32, 49, 0x00040000, -1, -1 },
|
||||
[Shortcut_SelectNextInputSource] = { "SelectNextInputSource", "Select next source in Input menu", YES, 32, 49, 0x000c0000, -1, -1 },
|
||||
[Shortcut_ShowSpotlight] = { "ShowSpotlight", "Show Spotlight Search", YES, 32, 49, 0x00100000, -1, -1 },
|
||||
[Shortcut_ShowFinderSearch] = { "ShowFinderSearch", "Show Finder search window", YES, 32, 49, 0x00180000, -1, -1 },
|
||||
[Shortcut_SwitchToDesktopLeft] = { "SwitchToDesktopLeft", "Move left a space", NO, 65535, 123, 0x00840000, -1, -1 },
|
||||
[Shortcut_SwitchToDesktopRight] = { "SwitchToDesktopRight", "Move right a space", NO, 65535, 124, 0x00840000, -1, -1 },
|
||||
[Shortcut_SwitchToDesktop1] = { "SwitchToDesktop1", "Switch to Desktop 1", NO, 65535, 18, 0x00040000, -1, -1 },
|
||||
[Shortcut_SwitchToDesktop2] = { "SwitchToDesktop2", "Switch to Desktop 2", NO, 65535, 19, 0x00040000, -1, -1 },
|
||||
[Shortcut_SwitchToDesktop3] = { "SwitchToDesktop3", "Switch to Desktop 3", NO, 65535, 20, 0x00040000, -1, -1 },
|
||||
[Shortcut_SwitchToDesktop4] = { "SwitchToDesktop4", "Switch to Desktop 4", NO, 65535, 21, 0x00040000, -1, -1 },
|
||||
[Shortcut_ShowContextualMenu] = { "ShowContextualMenu", "Show contextual menu", YES, 65535, 36, 0x00040000, 15, 0 },
|
||||
[Shortcut_ShowLaunchpad] = { "ShowLaunchpad", "Show Launchpad", NO, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_ShowAccessibilityControls] = { "ShowAccessibilityControls", "Show Accessibility controls", YES, 65535, 96, 0x00980000, -1, -1 },
|
||||
[Shortcut_ShowNotificationCenter] = { "ShowNotificationCenter", "Show Notification Center", NO, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_ToggleDoNotDisturb] = { "ToggleDoNotDisturb", "Turn Do Not Disturb on/off", YES, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_ToggleZoomFocusFollowing] = { "ToggleZoomFocusFollowing", "Zoom: Turn focus following on or off", NO, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_ScreenshotOptions] = { "ScreenshotOptions", "Screenshot and recording options", YES, 53, 23, 0x00120000, -1, -1 },
|
||||
[Shortcut_OpenQuickNote] = { "OpenQuickNote", "Quick note", YES, 113, 12, 0x00800000, -1, -1 },
|
||||
[Shortcut_ToggleStageManager] = { "ToggleStageManager", "Turn Stage Manager on/off", NO, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_TogglePresenterOverlayLarge] = { "TogglePresenterOverlayLarge", "Turn Presenter Overlay (large) on or off", YES, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_TogglePresenterOverlaySmall] = { "TogglePresenterOverlaySmall", "Turn Presenter Overlay (small) on or off", YES, 65535, 65535, 0, -1, -1 },
|
||||
[Shortcut_ToggleLiveSpeech] = { "ToggleLiveSpeech", "LiveSpeech: Turn Live Speech on or off", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_ToggleLiveSpeechVisibility] = { "ToggleLiveSpeechVisibility", "LiveSpeech: Toggle visibility", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_PauseOrResumeLiveSpeech] = { "PauseOrResumeLiveSpeech", "LiveSpeech: Pause or resume speech", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_CancelLiveSpeech] = { "CancelLiveSpeech", "LiveSpeech: Cancel speech", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_ToggleLiveSpeechPhrases] = { "ToggleLiveSpeechPhrases", "LiveSpeech: Hide or show phrases", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_ToggleSpeakSelection] = { "ToggleSpeakSelection", "Turn speak selection on or off", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_ToggleSpeakItemUnderPointer] = { "ToggleSpeakItemUnderPointer", "Turn speak item under the pointer on or off", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_ToggleTypingFeedback] = { "ToggleTypingFeedback", "Turn typing feedback on or off", YES, 65535, 65535, 0, 14, 0 },
|
||||
[Shortcut_MinimizeWindow] = { "MinimizeWindow", "Windows: Minimize", YES, 109, 46, 0x00100000, 15, 4 },
|
||||
[Shortcut_ZoomWindow] = { "ZoomWindow", "Windows: Zoom", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_FillWindow] = { "FillWindow", "Windows: Fill", YES, 102, 3, 0x00840000, 15, 4 },
|
||||
[Shortcut_CenterWindow] = { "CenterWindow", "Windows: Center", YES, 99, 8, 0x00840000, 15, 4 },
|
||||
[Shortcut_RestoreWindow] = { "RestoreWindow", "Windows: Return to Previous Size", YES, 114, 15, 0x00840000, 15, 4 },
|
||||
[Shortcut_TileLeftHalf] = { "TileLeftHalf", "Windows: Tile Left Half", YES, 65535, 123, 0x00840000, 15, 4 },
|
||||
[Shortcut_TileRightHalf] = { "TileRightHalf", "Windows: Tile Right Half", YES, 65535, 124, 0x00840000, 15, 4 },
|
||||
[Shortcut_TileTopHalf] = { "TileTopHalf", "Windows: Tile Top Half", YES, 65535, 126, 0x00840000, 15, 4 },
|
||||
[Shortcut_TileBottomHalf] = { "TileBottomHalf", "Windows: Tile Bottom Half", YES, 65535, 125, 0x00840000, 15, 4 },
|
||||
[Shortcut_TileTopLeftQuarter] = { "TileTopLeftQuarter", "Windows: Tile Top-Left Quarter", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_TileTopRightQuarter] = { "TileTopRightQuarter", "Windows: Tile Top-Right Quarter", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_TileBottomLeftQuarter] = { "TileBottomLeftQuarter", "Windows: Tile Bottom-Left Quarter", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_TileBottomRightQuarter] = { "TileBottomRightQuarter", "Windows: Tile Bottom-Right Quarter", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_ArrangeLeftRight] = { "ArrangeLeftRight", "Windows: Arrange Left and Right", YES, 65535, 123, 0x00860000, 15, 4 },
|
||||
[Shortcut_ArrangeRightLeft] = { "ArrangeRightLeft", "Windows: Arrange Right and Left", YES, 65535, 124, 0x00860000, 15, 4 },
|
||||
[Shortcut_ArrangeTopBottom] = { "ArrangeTopBottom", "Windows: Arrange Top and Bottom", YES, 65535, 126, 0x00860000, 15, 4 },
|
||||
[Shortcut_ArrangeBottomTop] = { "ArrangeBottomTop", "Windows: Arrange Bottom and Top", YES, 65535, 125, 0x00860000, 15, 4 },
|
||||
[Shortcut_ArrangeQuarters] = { "ArrangeQuarters", "Windows: Arrange in Quarters", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_FullScreenTileLeft] = { "FullScreenTileLeft", "Windows: Full-Screen Tile Left", YES, 65535, 65535, 0, 15, 4 },
|
||||
[Shortcut_FullScreenTileRight] = { "FullScreenTileRight", "Windows: Full-Screen Tile Right", YES, 65535, 65535, 0, 15, 4 },
|
||||
};
|
||||
|
||||
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
|
||||
@@ -482,8 +523,19 @@ static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymboli
|
||||
|
||||
for (int uid = 0; uid < numSymbolicHotkeys; ++uid) {
|
||||
struct SymbolicHotKey* hotkey = &hotkeys[uid];
|
||||
if (!hotkey->enabled) continue;
|
||||
if (hotkey->macOSVersion > macOSVersion.majorVersion) continue;
|
||||
|
||||
if (!hotkey->enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hotkey->macOSVersionMajor > macOSVersion.majorVersion ||
|
||||
(hotkey->macOSVersionMajor == macOSVersion.majorVersion && hotkey->macOSVersionMinor > macOSVersion.minorVersion)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hotkey->character == 0xFFFF && hotkey->key == 0xFFFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char keyCharBuf[64];
|
||||
const char *keyCharStr = keyCharBuf;
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#import "JNIUtilities.h"
|
||||
#import "sun_lwawt_macosx_CAccessibility.h"
|
||||
|
||||
static jclass sjc_CAccessibility = NULL;
|
||||
static jmethodID sjm_getScrollBar = NULL;
|
||||
|
||||
/*
|
||||
* Implementation of the accessibility peer for the ScrollArea role
|
||||
*/
|
||||
@@ -57,10 +60,30 @@
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
// Firstly, try to get the scroll bar using getHorizontalScrollBar/getVerticalScrollBar methods of JScrollPane.
|
||||
jobject scrollBar = NULL;
|
||||
GET_CACCESSIBILITY_CLASS_RETURN(nil);
|
||||
GET_STATIC_METHOD_RETURN(sjm_getScrollBar, sjc_CAccessibility, "getScrollBar",
|
||||
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)Ljavax/accessibility/Accessible;", nil);
|
||||
scrollBar = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getScrollBar, fAccessible, fComponent, orientation);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
if (scrollBar != NULL) {
|
||||
CommonComponentAccessibility *axScrollBar = nil;
|
||||
DECLARE_CLASS_RETURN(sjc_Accessible, "javax/accessibility/Accessible", nil);
|
||||
if ((*env)->IsInstanceOf(env, scrollBar, sjc_Accessible)) {
|
||||
axScrollBar = [CommonComponentAccessibility createWithAccessible:scrollBar withEnv:env withView:fView];
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, scrollBar);
|
||||
if (axScrollBar != nil) {
|
||||
return axScrollBar;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, try to search for the scroll bar within the children.
|
||||
NSArray *children = [CommonComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
|
||||
if ([children count] <= 0) return nil;
|
||||
|
||||
// The scroll bars are in the children.
|
||||
CommonComponentAccessibility *aElement;
|
||||
NSEnumerator *enumerator = [children objectEnumerator];
|
||||
while ((aElement = (CommonComponentAccessibility *)[enumerator nextObject])) {
|
||||
|
||||
@@ -126,7 +126,7 @@ typedef enum {
|
||||
- (void)dealloc;
|
||||
|
||||
- (void)handleDisplayLink:(BOOL)enabled displayID:(jint)displayID source:(const char*)src;
|
||||
- (void)createDisplayLinkIfAbsent: (jint)displayID;
|
||||
- (void)createDisplayLinkIfAbsent: (NSNumber*)displayID;
|
||||
|
||||
/**
|
||||
* Resets the current clip state (disables both scissor and depth tests).
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
// to avoid multiple start/stop displaylink operations. It speeds up
|
||||
// scenarios with multiple subsequent updates.
|
||||
#define KEEP_ALIVE_COUNT 4
|
||||
#define CV_DISPLAYLINK_FAIL_DELAY 1.0
|
||||
#define MAX_DISPLAYLINK_FAIL_COUNT 5
|
||||
|
||||
#define TO_MS(x) (1000.0 * (x))
|
||||
#define TO_FPS(x) (1.0 / (x))
|
||||
@@ -98,6 +100,7 @@ typedef struct {
|
||||
CVDisplayLinkRef displayLink;
|
||||
MTLContext* mtlc;
|
||||
jint redrawCount;
|
||||
jint failCount;
|
||||
|
||||
jint avgDisplayLinkSamples;
|
||||
CFTimeInterval lastRedrawTime;
|
||||
@@ -330,13 +333,13 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
case MTLDCM_DISPLAY_WAKEUP:
|
||||
if (active) {
|
||||
// (if needed will start a new display link thread):
|
||||
[mtlc createDisplayLinkIfAbsent:displayID];
|
||||
[mtlc createDisplayLinkIfAbsent:@(displayID)];
|
||||
}
|
||||
break;
|
||||
case MTLDCM_DISPLAY_RECONFIGURE:
|
||||
if (active) {
|
||||
// (if needed will start a new display link thread):
|
||||
[mtlc createDisplayLinkIfAbsent:displayID];
|
||||
[mtlc createDisplayLinkIfAbsent:@(displayID)];
|
||||
} else {
|
||||
// kill CVDisplayLinks for inactive displays:
|
||||
[mtlc destroyDisplayLink:displayID];
|
||||
@@ -410,7 +413,7 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
[device release];
|
||||
}
|
||||
// (will start a new display link thread if needed):
|
||||
[mtlc createDisplayLinkIfAbsent:displayID];
|
||||
[mtlc createDisplayLinkIfAbsent:@(displayID)];
|
||||
return mtlc;
|
||||
}
|
||||
|
||||
@@ -493,27 +496,47 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
return [_displayLinkStates allKeys];
|
||||
}
|
||||
|
||||
- (void)createDisplayLinkIfAbsent: (jint)displayID {
|
||||
- (void)createDisplayLinkIfAbsent: (NSNumber*)displayID {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
if (_displayLinkStates != nil) {
|
||||
MTLDisplayLinkState *dlState = [self getDisplayLinkState:displayID];
|
||||
MTLDisplayLinkState *dlState = [self getDisplayLinkState:[displayID intValue]];
|
||||
if ((dlState != nil) && (dlState->displayLink != nil)) {
|
||||
return;
|
||||
}
|
||||
if (TRACE_DISPLAY) {
|
||||
dumpDisplayInfo(displayID);
|
||||
dumpDisplayInfo([displayID intValue]);
|
||||
}
|
||||
CVDisplayLinkRef _displayLink;
|
||||
if (TRACE_CVLINK) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "MTLContext_createDisplayLinkIfAbsent: "
|
||||
"ctx=%p displayID=%d", self, displayID);
|
||||
"ctx=%p displayID=%d", self, [displayID intValue]);
|
||||
}
|
||||
|
||||
CHECK_CVLINK("CreateWithCGDisplay", nil, &_displayLink,
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &_displayLink));
|
||||
CVDisplayLinkCreateWithCGDisplay([displayID intValue], &_displayLink));
|
||||
|
||||
if (_displayLink == nil) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLContext_createDisplayLinkIfAbsent: Failed to initialize CVDisplayLink.");
|
||||
|
||||
if (dlState == nil) {
|
||||
dlState = malloc(sizeof(MTLDisplayLinkState));
|
||||
dlState->displayID = [displayID intValue];
|
||||
dlState->displayLink = nil;
|
||||
dlState->failCount = 0;
|
||||
_displayLinkStates[displayID] = [NSValue valueWithPointer:dlState];
|
||||
}
|
||||
|
||||
if (dlState->failCount >= MAX_DISPLAYLINK_FAIL_COUNT) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR,
|
||||
"MTLLayer.createDisplayLink --- unable to create CVDisplayLink.");
|
||||
dlState->failCount = 0;
|
||||
return;
|
||||
}
|
||||
dlState->failCount++;
|
||||
[self performSelector:@selector(createDisplayLinkIfAbsent:)
|
||||
withObject:displayID
|
||||
afterDelay:CV_DISPLAYLINK_FAIL_DELAY];
|
||||
} else {
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, "MTLContext_createDisplayLinkIfAbsent["
|
||||
"ctx=%p displayID=%d] displayLink=%p",
|
||||
@@ -524,11 +547,12 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
isNewDisplayLink = true;
|
||||
}
|
||||
// update:
|
||||
dlState->displayID = displayID;
|
||||
dlState->displayID = [displayID intValue];
|
||||
dlState->displayLink = _displayLink;
|
||||
dlState->mtlc = self;
|
||||
|
||||
dlState->redrawCount = 0;
|
||||
dlState->failCount = 0;
|
||||
dlState->avgDisplayLinkSamples = 0;
|
||||
dlState->lastRedrawTime = 0.0;
|
||||
dlState->lastDisplayLinkTime = 0.0;
|
||||
@@ -537,7 +561,7 @@ extern void initSamplers(id<MTLDevice> device);
|
||||
|
||||
if (isNewDisplayLink) {
|
||||
// publish fully initialized object:
|
||||
_displayLinkStates[@(displayID)] = [NSValue valueWithPointer:dlState];
|
||||
_displayLinkStates[displayID] = [NSValue valueWithPointer:dlState];
|
||||
}
|
||||
|
||||
CHECK_CVLINK("SetOutputCallback", nil, &_displayLink,
|
||||
|
||||
@@ -173,6 +173,10 @@ public abstract class SunDropTargetContextPeer implements DropTargetContextPeer,
|
||||
return currentA;
|
||||
}
|
||||
|
||||
protected int getDropAction() {
|
||||
return currentDA;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Transferable associated with the drop
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ class VKBufImgOps extends BufferedBufImgOps {
|
||||
/**
|
||||
* This method is called from VKDrawImage.transformImage() only. It
|
||||
* validates the provided BufferedImageOp to determine whether the op
|
||||
* is one that can be accelerated by the MTL pipeline. If the operation
|
||||
* is one that can be accelerated by the Vulkan pipeline. If the operation
|
||||
* cannot be completed for any reason, this method returns false;
|
||||
* otherwise, the given BufferedImage is rendered to the destination
|
||||
* using the provided BufferedImageOp and this method returns true.
|
||||
@@ -53,65 +53,66 @@ class VKBufImgOps extends BufferedBufImgOps {
|
||||
static boolean renderImageWithOp(SunGraphics2D sg, BufferedImage img,
|
||||
BufferedImageOp biop, int x, int y)
|
||||
{
|
||||
// Validate the provided BufferedImage (make sure it is one that
|
||||
// is supported, and that its properties are acceleratable)
|
||||
if (biop instanceof ConvolveOp) {
|
||||
if (!isConvolveOpValid((ConvolveOp)biop)) {
|
||||
return false;
|
||||
}
|
||||
} else if (biop instanceof RescaleOp) {
|
||||
if (!isRescaleOpValid((RescaleOp)biop, img)) {
|
||||
return false;
|
||||
}
|
||||
} else if (biop instanceof LookupOp) {
|
||||
if (!isLookupOpValid((LookupOp)biop, img)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// No acceleration for other BufferedImageOps (yet)
|
||||
return false;
|
||||
}
|
||||
|
||||
SurfaceData dstData = sg.surfaceData;
|
||||
if (!(dstData instanceof VKSurfaceData) ||
|
||||
(sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
|
||||
(sg.compositeState > SunGraphics2D.COMP_ALPHA))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SurfaceData srcData =
|
||||
dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
|
||||
CompositeType.SrcOver, null);
|
||||
if (!(srcData instanceof VKSurfaceData)) {
|
||||
// REMIND: this hack tries to ensure that we have a cached texture
|
||||
srcData =
|
||||
dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
|
||||
CompositeType.SrcOver, null);
|
||||
if (!(srcData instanceof VKSurfaceData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the source surface is actually a texture and
|
||||
// that the operation is supported
|
||||
VKSurfaceData vkSrc = (VKSurfaceData)srcData;
|
||||
VKGraphicsConfig gc = vkSrc.getGraphicsConfig();
|
||||
if (vkSrc.getType() != VKSurfaceData.TEXTURE || !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int sw = img.getWidth();
|
||||
int sh = img.getHeight();
|
||||
VKBlitLoops.IsoBlit(srcData, dstData,
|
||||
img, biop,
|
||||
sg.composite, sg.getCompClip(),
|
||||
sg.transform, sg.interpolationType,
|
||||
0, 0, sw, sh,
|
||||
x, y, x+sw, y+sh,
|
||||
true);
|
||||
|
||||
return true;
|
||||
// TODO No acceleration for image ops yet.
|
||||
return false;
|
||||
// // Validate the provided BufferedImage (make sure it is one that
|
||||
// // is supported, and that its properties are acceleratable)
|
||||
// if (biop instanceof ConvolveOp) {
|
||||
// if (!isConvolveOpValid((ConvolveOp)biop)) {
|
||||
// return false;
|
||||
// }
|
||||
// } else if (biop instanceof RescaleOp) {
|
||||
// if (!isRescaleOpValid((RescaleOp)biop, img)) {
|
||||
// return false;
|
||||
// }
|
||||
// } else if (biop instanceof LookupOp) {
|
||||
// if (!isLookupOpValid((LookupOp)biop, img)) {
|
||||
// return false;
|
||||
// }
|
||||
// } else {
|
||||
// // No acceleration for other BufferedImageOps (yet)
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// SurfaceData dstData = sg.surfaceData;
|
||||
// if (!(dstData instanceof VKSurfaceData) ||
|
||||
// (sg.interpolationType == AffineTransformOp.TYPE_BICUBIC) ||
|
||||
// (sg.compositeState > SunGraphics2D.COMP_ALPHA))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// SurfaceData srcData =
|
||||
// dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
|
||||
// CompositeType.SrcOver, null);
|
||||
// if (!(srcData instanceof VKSurfaceData)) {
|
||||
// // REMIND: this hack tries to ensure that we have a cached texture
|
||||
// srcData =
|
||||
// dstData.getSourceSurfaceData(img, SunGraphics2D.TRANSFORM_ISIDENT,
|
||||
// CompositeType.SrcOver, null);
|
||||
// if (!(srcData instanceof VKSurfaceData)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Verify that the source surface is actually a texture and
|
||||
// // that the operation is supported
|
||||
// VKSurfaceData vkSrc = (VKSurfaceData)srcData;
|
||||
// VKGraphicsConfig gc = vkSrc.getGraphicsConfig();
|
||||
// if (vkSrc.getType() != VKSurfaceData.TEXTURE || !gc.isCapPresent(CAPS_EXT_BIOP_SHADER))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// int sw = img.getWidth();
|
||||
// int sh = img.getHeight();
|
||||
// VKBlitLoops.IsoBlit(srcData, dstData,
|
||||
// img, biop,
|
||||
// sg.composite, sg.getCompClip(),
|
||||
// sg.transform, sg.interpolationType,
|
||||
// 0, 0, sw, sh,
|
||||
// x, y, x+sw, y+sh);
|
||||
//
|
||||
// return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import sun.java2d.pipe.RenderQueue;
|
||||
import sun.java2d.pipe.hw.ContextCapabilities;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.BufferCapabilities;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.lang.annotation.Native;
|
||||
|
||||
/**
|
||||
@@ -41,6 +43,8 @@ final class VKContext extends BufferedContext {
|
||||
private static final PlatformLogger log =
|
||||
PlatformLogger.getLogger("sun.java2d.vulkan.VKContext");
|
||||
|
||||
public static final VKContext INSTANCE = new VKContext(VKRenderQueue.getInstance());
|
||||
|
||||
public VKContext(RenderQueue rq) {
|
||||
super(rq);
|
||||
}
|
||||
@@ -73,6 +77,26 @@ final class VKContext extends BufferedContext {
|
||||
@Native
|
||||
static final int CAPS_EXT_GRAD_SHADER = (FIRST_PRIVATE_CAP << 3);
|
||||
|
||||
public static final VKContextCaps CONTEXT_CAPS = new VKContextCaps(
|
||||
CAPS_PS30 | CAPS_PS20 | CAPS_RT_TEXTURE_ALPHA |
|
||||
CAPS_RT_TEXTURE_OPAQUE | CAPS_MULTITEXTURE | CAPS_TEXNONPOW2 |
|
||||
CAPS_TEXNONSQUARE, null);
|
||||
|
||||
public static final ImageCapabilities IMAGE_CAPS = new ImageCapabilities(true) {
|
||||
@Override
|
||||
public boolean isTrueVolatile() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static final BufferCapabilities BUFFER_CAPS = new BufferCapabilities(IMAGE_CAPS, IMAGE_CAPS,
|
||||
BufferCapabilities.FlipContents.COPIED) {
|
||||
@Override
|
||||
public boolean isMultiBufferAvailable() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public VKContextCaps(int caps, String adapterId) {
|
||||
super(caps, adapterId);
|
||||
}
|
||||
|
||||
@@ -50,13 +50,6 @@ public class VKDrawImage extends DrawImage {
|
||||
// punt to the MediaLib-based transformImage() in the superclass if:
|
||||
// - bicubic interpolation is specified
|
||||
// - a background color is specified and will be used
|
||||
// - the source surface is neither a texture nor render-to-texture
|
||||
// surface, and a non-default interpolation hint is specified
|
||||
// (we can only control the filtering for texture->surface
|
||||
// copies)
|
||||
// REMIND: we should tweak the sw->texture->surface
|
||||
// transform case to handle filtering appropriately
|
||||
// (see 4841762)...
|
||||
// - an appropriate TransformBlit primitive could not be found
|
||||
if (interpType != AffineTransformOp.TYPE_BICUBIC) {
|
||||
SurfaceData dstData = sg.surfaceData;
|
||||
@@ -66,12 +59,7 @@ public class VKDrawImage extends DrawImage {
|
||||
sg.imageComp,
|
||||
bgColor);
|
||||
|
||||
if (srcData != null &&
|
||||
!isBgOperation(srcData, bgColor) &&
|
||||
(srcData.getSurfaceType() == VKSurfaceData.VKTexture ||
|
||||
srcData.getSurfaceType() == VKSurfaceData.VKSurfaceRTT ||
|
||||
interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR))
|
||||
{
|
||||
if (srcData != null && !isBgOperation(srcData, bgColor)) {
|
||||
SurfaceType srcType = srcData.getSurfaceType();
|
||||
SurfaceType dstType = dstData.getSurfaceType();
|
||||
TransformBlit blit = TransformBlit.getFromCache(srcType,
|
||||
|
||||
141
src/java.desktop/share/classes/sun/java2d/vulkan/VKEnv.java
Normal file
141
src/java.desktop/share/classes/sun/java2d/vulkan/VKEnv.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class VKEnv {
|
||||
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.VKInstance");
|
||||
|
||||
private static final class Options {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean vulkan = "true".equalsIgnoreCase(AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan", "")));
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean accelsd = vulkan && "true".equalsIgnoreCase(AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", "")));
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static final int deviceNumber = !vulkan ? 0 : AccessController.doPrivileged(
|
||||
(PrivilegedAction<Integer>) () -> Integer.getInteger("sun.java2d.vulkan.deviceNumber", 0));
|
||||
}
|
||||
|
||||
private static final int UNINITIALIZED = 0;
|
||||
private static final int INITIALIZING = 1;
|
||||
private static final int DISABLED = 2;
|
||||
private static final int ENABLED = 3;
|
||||
private static final int ACCELSD_BIT = 4;
|
||||
private static final int PRESENT_BIT = 8;
|
||||
|
||||
private static int state = UNINITIALIZED;
|
||||
private static VKGPU[] devices;
|
||||
private static VKGPU defaultDevice;
|
||||
|
||||
private static native long initPlatform(long nativePtr);
|
||||
private static native VKGPU[] initNative(long platformData);
|
||||
|
||||
public static synchronized void init(long nativePtr) {
|
||||
if (state > INITIALIZING) return;
|
||||
long platformData = nativePtr == 0 ? 0 : initPlatform(nativePtr);
|
||||
int newState = DISABLED;
|
||||
if (Options.vulkan) {
|
||||
devices = initNative(platformData);
|
||||
if (devices != null) {
|
||||
newState = ENABLED;
|
||||
if (Options.accelsd) newState |= ACCELSD_BIT;
|
||||
defaultDevice = devices[Options.deviceNumber >= 0 && Options.deviceNumber < devices.length ?
|
||||
Options.deviceNumber : 0];
|
||||
// Check whether the presentation is supported.
|
||||
for (VKGPU device : devices) {
|
||||
if (device.hasCap(VKGPU.CAP_PRESENTABLE_BIT) &&
|
||||
device.getPresentableGraphicsConfigs().findAny().isPresent()) {
|
||||
newState |= PRESENT_BIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VKBlitLoops.register();
|
||||
VKMaskFill.register();
|
||||
VKMaskBlit.register();
|
||||
}
|
||||
}
|
||||
state = newState;
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
if (isVulkanEnabled()) {
|
||||
log.fine("Vulkan rendering enabled: YES" +
|
||||
"\n presentation enabled: " + (isPresentationEnabled() ? "YES" : "NO") +
|
||||
"\n accelerated surface data enabled: " + (isSurfaceDataAccelerated() ? "YES" : "NO") +
|
||||
"\n devices:" + Stream.of(devices).map(d -> (d == defaultDevice ?
|
||||
"\n *" : "\n ") + d.getName()).collect(Collectors.joining()));
|
||||
} else log.fine("Vulkan rendering enabled: NO");
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkInit() {
|
||||
if (state > INITIALIZING) return;
|
||||
synchronized (VKEnv.class) {
|
||||
if (state == UNINITIALIZED) {
|
||||
// Try initializing the Toolkit first to give it a chance to init Vulkan with proper platform data.
|
||||
state = INITIALIZING;
|
||||
Toolkit.getDefaultToolkit();
|
||||
}
|
||||
// Still not initialized? Init without platform data.
|
||||
if (state == INITIALIZING) init(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isVulkanEnabled() {
|
||||
checkInit();
|
||||
return (state & ENABLED) == ENABLED;
|
||||
}
|
||||
|
||||
public static boolean isPresentationEnabled() {
|
||||
checkInit();
|
||||
return (state & PRESENT_BIT) != 0;
|
||||
}
|
||||
|
||||
public static boolean isSurfaceDataAccelerated() {
|
||||
checkInit();
|
||||
return (state & ACCELSD_BIT) != 0;
|
||||
}
|
||||
|
||||
public static Stream<VKGPU> getDevices() {
|
||||
checkInit();
|
||||
final VKGPU first = defaultDevice;
|
||||
return Stream.concat(Stream.of(first), Stream.of(devices).filter(d -> d != first));
|
||||
}
|
||||
}
|
||||
173
src/java.desktop/share/classes/sun/java2d/vulkan/VKFormat.java
Normal file
173
src/java.desktop/share/classes/sun/java2d/vulkan/VKFormat.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.PixelInterleavedSampleModel;
|
||||
import java.awt.image.SinglePixelPackedSampleModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.nio.ByteOrder;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import sun.awt.image.BufImgSurfaceData;
|
||||
import sun.awt.image.ByteComponentRaster;
|
||||
import sun.awt.image.IntegerComponentRaster;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.loops.SurfaceType;
|
||||
|
||||
/**
|
||||
* Vulkan format description, which allows creation of compatible BufferedImages.
|
||||
*/
|
||||
public enum VKFormat {
|
||||
// VK_FORMAT_B8G8R8A8_UNORM doesn't have a matching standard format in Java,
|
||||
// but it can be aliased as TYPE_INT_ARGB on little-endian systems.
|
||||
B8G8R8A8_UNORM(44,
|
||||
LEOptimizations.ENABLED ? VKFormatModel.INT_ARGB_PRE : VKFormatModel.CUSTOM_4BYTE_BGRA_PRE,
|
||||
LEOptimizations.ENABLED ? VKFormatModel.INT_RGB : VKFormatModel.CUSTOM_4BYTE_BGRx),
|
||||
|
||||
R8G8B8A8_UNORM(37, VKFormatModel.CUSTOM_4BYTE_RGBA_PRE, VKFormatModel.CUSTOM_4BYTE_RGBx),
|
||||
|
||||
A8B8G8R8_UNORM_PACK32(51, VKFormatModel.CUSTOM_INT_ABGR_PRE, VKFormatModel.INT_BGR);
|
||||
|
||||
private final int value;
|
||||
private final SurfaceType surfaceType, translucentSurfaceType, opaqueSurfaceType;
|
||||
private final VKFormatModel translucentModel, opaqueModel;
|
||||
private final VKBufImgGraphicsConfig bufferedGraphicsConfig = new VKBufImgGraphicsConfig(this);
|
||||
|
||||
VKFormat(int value, VKFormatModel translucentModel, VKFormatModel opaqueModel) {
|
||||
this.value = value;
|
||||
this.surfaceType = VKSurfaceData.VKSurface.deriveSubType("Vulkan surface (" + name() + ")");
|
||||
this.translucentSurfaceType = translucentModel == null ? null :
|
||||
this.surfaceType.deriveSubType("Vulkan surface (" + name() + ", TRANSLUCENT)");
|
||||
this.opaqueSurfaceType = this.surfaceType.deriveSubType("Vulkan surface (" + name() + ", OPAQUE)");
|
||||
this.translucentModel = translucentModel;
|
||||
this.opaqueModel = opaqueModel;
|
||||
}
|
||||
|
||||
public int getValue(int transparency) {
|
||||
final int FORMAT_OPAQUE_BIT = 0x80000000;
|
||||
return transparency != Transparency.OPAQUE ? value : value | FORMAT_OPAQUE_BIT;
|
||||
}
|
||||
|
||||
public SurfaceType getSurfaceType(int transparency) {
|
||||
return switch (transparency) {
|
||||
case 0 -> surfaceType; // Any transparency.
|
||||
case Transparency.TRANSLUCENT, Transparency.BITMASK -> translucentSurfaceType;
|
||||
case Transparency.OPAQUE -> opaqueSurfaceType;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public VKFormatModel getFormatModel(int transparency) {
|
||||
return transparency != Transparency.OPAQUE ? translucentModel : opaqueModel;
|
||||
}
|
||||
|
||||
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
|
||||
VKFormatModel formatModel = getFormatModel(transparency);
|
||||
ColorModel colorModel = formatModel.getColorModel();
|
||||
SampleModel sampleModel = formatModel.createSampleModel(width, height);
|
||||
SurfaceType surfaceType = formatModel.getSurfaceType();
|
||||
WritableRaster raster = Raster.createWritableRaster(sampleModel, null);
|
||||
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
|
||||
VKBufImgSurfaceData surfaceData = new VKBufImgSurfaceData(bufferedGraphicsConfig, raster, image, surfaceType);
|
||||
SurfaceManager.setManager(image, new VKBufImgSurfaceManager(image, surfaceData));
|
||||
return image;
|
||||
}
|
||||
|
||||
public boolean isTranslucencyCapable() {
|
||||
return translucentModel != VKFormatModel.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some Vulkan formats can be more efficiently aliased as built-in Java formats on little-endian systems.
|
||||
*/
|
||||
private interface LEOptimizations {
|
||||
@SuppressWarnings("removal")
|
||||
boolean ENABLED = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN &&
|
||||
"true".equalsIgnoreCase(AccessController.doPrivileged((PrivilegedAction<String>) () ->
|
||||
System.getProperty("sun.java2d.vulkan.leOptimizations", "true")));
|
||||
}
|
||||
|
||||
private static class VKBufImgSurfaceManager extends SurfaceManager {
|
||||
private final BufferedImage image;
|
||||
private final VKBufImgSurfaceData sd;
|
||||
private VKBufImgSurfaceManager(BufferedImage image, VKBufImgSurfaceData sd) {
|
||||
this.image = image;
|
||||
this.sd = sd;
|
||||
}
|
||||
public SurfaceData getPrimarySurfaceData() { return sd; }
|
||||
public SurfaceData restoreContents() { return sd; }
|
||||
}
|
||||
|
||||
private static class VKBufImgSurfaceData extends BufImgSurfaceData {
|
||||
private final GraphicsConfiguration gc;
|
||||
private VKBufImgSurfaceData(GraphicsConfiguration gc,
|
||||
WritableRaster raster, BufferedImage image, SurfaceType surfaceType) {
|
||||
super(raster.getDataBuffer(), image, surfaceType, 1, 1);
|
||||
this.gc = gc;
|
||||
|
||||
Object array;
|
||||
if (raster instanceof IntegerComponentRaster r) array = r.getDataStorage();
|
||||
else if (raster instanceof ByteComponentRaster r) array = r.getDataStorage();
|
||||
else throw new IllegalArgumentException("Unsupported raster type: " + raster.getClass().getCanonicalName());
|
||||
|
||||
int pixStr, scanStr;
|
||||
if (raster.getSampleModel() instanceof PixelInterleavedSampleModel sm) {
|
||||
pixStr = sm.getPixelStride();
|
||||
scanStr = sm.getScanlineStride();
|
||||
} else if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel sm) {
|
||||
pixStr = DataBuffer.getDataTypeSize(sm.getDataType()) / 8;
|
||||
scanStr = sm.getScanlineStride() * pixStr;
|
||||
} else throw new IllegalArgumentException("Unsupported sample model: " +
|
||||
raster.getSampleModel().getClass().getCanonicalName());
|
||||
|
||||
initRaster(array, 0, 0, image.getWidth(), image.getHeight(), pixStr, scanStr, null);
|
||||
initSolidLoops();
|
||||
}
|
||||
@Override
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
return gc;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VKBufImgGraphicsConfig extends VKOffscreenGraphicsConfig {
|
||||
private VKBufImgGraphicsConfig(VKFormat format) {
|
||||
super(null, format);
|
||||
}
|
||||
@Override
|
||||
public VKGPU getGPU() {
|
||||
throw new UnsupportedOperationException("No VKGPU associated with VKBufImgGraphicsConfig");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.PixelInterleavedSampleModel;
|
||||
import java.awt.image.SampleModel;
|
||||
|
||||
import sun.awt.image.PixelConverter;
|
||||
import sun.java2d.loops.SurfaceType;
|
||||
|
||||
import static java.awt.image.DataBuffer.TYPE_BYTE;
|
||||
import static java.awt.image.DataBuffer.TYPE_INT;
|
||||
import static java.awt.Transparency.OPAQUE;
|
||||
import static java.awt.Transparency.TRANSLUCENT;
|
||||
|
||||
/**
|
||||
* Format model describes properties of the surface, necessary for the creation of compatible BufferedImages.
|
||||
*/
|
||||
public enum VKFormatModel {
|
||||
NONE(BufferedImage.TYPE_CUSTOM, null, null, null, null),
|
||||
|
||||
INT_ARGB_PRE(BufferedImage.TYPE_INT_ARGB_PRE, SurfaceType.IntArgbPre, PixelConverter.ArgbPre.instance,
|
||||
new DirectColorModel(sRGB(), 32, 0xff0000, 0xff00, 0xff, 0xff000000, true, TYPE_INT), null),
|
||||
|
||||
INT_RGB(BufferedImage.TYPE_INT_RGB, SurfaceType.IntRgb, PixelConverter.Xrgb.instance,
|
||||
new DirectColorModel(sRGB(), 24, 0xff0000, 0xff00, 0xff, 0x00000000, false, TYPE_INT), null),
|
||||
|
||||
CUSTOM_4BYTE_BGRA_PRE(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, PixelConverter.ArgbPre.instance,
|
||||
new ComponentColorModel(sRGB(), true, true, TRANSLUCENT, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 2, 1, 0, 3)),
|
||||
|
||||
CUSTOM_4BYTE_BGRx(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, PixelConverter.Xrgb.instance,
|
||||
new ComponentColorModel(sRGB(), false, false, OPAQUE, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 2, 1, 0)),
|
||||
|
||||
CUSTOM_4BYTE_RGBA_PRE(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, CustomPixelConverter.AbgrPre,
|
||||
new ComponentColorModel(sRGB(), true, true, TRANSLUCENT, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 0, 1, 2, 3)),
|
||||
|
||||
CUSTOM_4BYTE_RGBx(BufferedImage.TYPE_CUSTOM, SurfaceType.Any4Byte, PixelConverter.Xbgr.instance,
|
||||
new ComponentColorModel(sRGB(), false, false, OPAQUE, TYPE_BYTE), sampleModel(TYPE_BYTE, 4, 0, 1, 2)),
|
||||
|
||||
CUSTOM_INT_ABGR_PRE(BufferedImage.TYPE_CUSTOM, SurfaceType.AnyDcm, CustomPixelConverter.AbgrPre,
|
||||
new DirectColorModel(sRGB(), 32, 0xff, 0xff00, 0xff0000, 0xff000000, true, TYPE_INT), null),
|
||||
|
||||
INT_BGR(BufferedImage.TYPE_INT_BGR, SurfaceType.IntBgr, PixelConverter.Xbgr.instance,
|
||||
new DirectColorModel(sRGB(), 24, 0xff, 0xff00, 0xff0000, 0x00000000, false, TYPE_INT), null);
|
||||
|
||||
private final int type;
|
||||
private final SurfaceType surfaceType;
|
||||
private final ColorModel colorModel;
|
||||
private final SampleModelFactory sampleModelFactory;
|
||||
|
||||
VKFormatModel(int type, SurfaceType surfaceType, PixelConverter pixelConverter,
|
||||
ColorModel colorModel, SampleModelFactory sampleModelFactory) {
|
||||
this.type = type;
|
||||
this.surfaceType = surfaceType == null ? null : surfaceType.deriveSubType(
|
||||
"Vulkan-compatible buffered surface (" + surfaceType.getDescriptor() + ")", pixelConverter);
|
||||
this.colorModel = colorModel;
|
||||
this.sampleModelFactory = sampleModelFactory == null && colorModel != null ?
|
||||
this.colorModel::createCompatibleSampleModel : sampleModelFactory;
|
||||
}
|
||||
|
||||
public SurfaceType getSurfaceType() {
|
||||
return surfaceType;
|
||||
}
|
||||
|
||||
public ColorModel getColorModel() {
|
||||
return colorModel;
|
||||
}
|
||||
|
||||
public SampleModel createSampleModel(int width, int height) {
|
||||
return sampleModelFactory.createSampleModel(width, height);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface SampleModelFactory {
|
||||
SampleModel createSampleModel(int w, int h);
|
||||
}
|
||||
|
||||
private static SampleModelFactory sampleModel(int dataType, int components, int... bandOffsets) {
|
||||
return (w, h) -> new PixelInterleavedSampleModel(dataType, w, h, components, w*components, bandOffsets);
|
||||
}
|
||||
|
||||
private static ColorSpace sRGB() {
|
||||
return ColorSpace.getInstance(ColorSpace. CS_sRGB);
|
||||
}
|
||||
|
||||
private static abstract class CustomPixelConverter extends PixelConverter {
|
||||
|
||||
private static final PixelConverter AbgrPre = new CustomPixelConverter(0xff000000) {
|
||||
@Override
|
||||
public int rgbToPixel(int rgb, ColorModel cm) {
|
||||
int a = rgb >>> 24;
|
||||
int r = (rgb >> 16) & 0xff;
|
||||
int g = (rgb >> 8) & 0xff;
|
||||
int b = (rgb ) & 0xff;
|
||||
int a2 = a + (a >> 7);
|
||||
r = (r * a2) >> 8;
|
||||
g = (g * a2) >> 8;
|
||||
b = (b * a2) >> 8;
|
||||
return ((a << 24) | (b << 16) | (g << 8) | (r));
|
||||
}
|
||||
@Override
|
||||
public int pixelToRgb(int pixel, ColorModel cm) {
|
||||
int a = pixel >>> 24;
|
||||
int r = (pixel ) & 0xff;
|
||||
int g = (pixel >> 8) & 0xff;
|
||||
int b = (pixel >> 16) & 0xff;
|
||||
if (a != 0) {
|
||||
r = ((r << 8) - r) / a;
|
||||
g = ((g << 8) - g) / a;
|
||||
b = ((b << 8) - b) / a;
|
||||
}
|
||||
return ((a << 24) | (r << 16) | (g << 8) | (b));
|
||||
}
|
||||
};
|
||||
|
||||
private CustomPixelConverter(int alphaMask) { this.alphaMask = alphaMask; }
|
||||
@Override
|
||||
public abstract int rgbToPixel(int rgb, ColorModel cm);
|
||||
@Override
|
||||
public abstract int pixelToRgb(int pixel, ColorModel cm);
|
||||
}
|
||||
}
|
||||
135
src/java.desktop/share/classes/sun/java2d/vulkan/VKGPU.java
Normal file
135
src/java.desktop/share/classes/sun/java2d/vulkan/VKGPU.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import sun.awt.image.SurfaceManager;
|
||||
|
||||
import java.awt.Transparency;
|
||||
import java.lang.annotation.Native;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* VKDevice wrapper.
|
||||
*/
|
||||
public class VKGPU {
|
||||
|
||||
@Native public static final int CAP_PRESENTABLE_BIT = 0x80000000;
|
||||
@Native public static final int CAP_LOGIC_OP_BIT = 0x40000000;
|
||||
@Native public static final int CAP_SAMPLED_4BYTE_BIT = 0; // Considered always supported.
|
||||
@Native public static final int CAP_SAMPLED_3BYTE_BIT = 1;
|
||||
@Native public static final int CAP_SAMPLED_565_BIT = 2;
|
||||
@Native public static final int CAP_SAMPLED_555_BIT = 4;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache();
|
||||
private final long nativeHandle;
|
||||
private final String name;
|
||||
private final Type type;
|
||||
private final int caps;
|
||||
private final List<VKGraphicsConfig> offscreenGraphicsConfigs, presentableGraphicsConfigs;
|
||||
|
||||
private static native void init(long nativeHandle);
|
||||
private static native void reset(long nativeHandle);
|
||||
|
||||
/**
|
||||
* Instantiated from native code, see createJavaDevices in VKInstance.c
|
||||
* Fresh devices are created in uninitialized state. They can be queried for their properties
|
||||
* but cannot be used for rendering until initialized via getNativeHandle().
|
||||
*/
|
||||
private VKGPU(long nativeHandle, String name, int type, int caps, int[] supportedFormats) {
|
||||
this.nativeHandle = nativeHandle;
|
||||
this.name = name;
|
||||
this.type = Type.VALUES[type];
|
||||
this.caps = caps;
|
||||
offscreenGraphicsConfigs = new ArrayList<>();
|
||||
presentableGraphicsConfigs = new ArrayList<>();
|
||||
VKFormat[] allFormats = VKFormat.values();
|
||||
for (int supportedFormat : supportedFormats) {
|
||||
int formatValue = supportedFormat & ~CAP_PRESENTABLE_BIT;
|
||||
for (VKFormat format : allFormats) {
|
||||
if (formatValue == format.getValue(Transparency.TRANSLUCENT)) {
|
||||
VKOffscreenGraphicsConfig gc = new VKOffscreenGraphicsConfig(this, format);
|
||||
offscreenGraphicsConfigs.add(gc);
|
||||
if ((supportedFormat & caps & CAP_PRESENTABLE_BIT) != 0) presentableGraphicsConfigs.add(gc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { return surfaceDataProxyCache; }
|
||||
public String getName() { return name; }
|
||||
public Type getType() { return type; }
|
||||
|
||||
public Stream<VKGraphicsConfig> getOffscreenGraphicsConfigs() {
|
||||
return offscreenGraphicsConfigs.stream();
|
||||
}
|
||||
|
||||
public Stream<VKGraphicsConfig> getPresentableGraphicsConfigs() {
|
||||
return presentableGraphicsConfigs.stream();
|
||||
}
|
||||
|
||||
public int getCaps() {
|
||||
return caps;
|
||||
}
|
||||
|
||||
public boolean hasCap(int cap) {
|
||||
return (caps & cap) == cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the device and return its native handle.
|
||||
*/
|
||||
public synchronized long getNativeHandle() {
|
||||
if (!initialized) {
|
||||
try {
|
||||
init(nativeHandle);
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Failed to initialize Vulkan device: " + name, e);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
return nativeHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (" + type + ")";
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
OTHER,
|
||||
INTEGRATED_GPU,
|
||||
DISCRETE_GPU,
|
||||
VIRTUAL_GPU,
|
||||
CPU;
|
||||
private static final Type[] VALUES = values();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,9 +26,124 @@
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.VolatileImage;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.SurfaceManager;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.Surface;
|
||||
import sun.java2d.SurfaceManagerFactory;
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
import sun.java2d.pipe.hw.AccelGraphicsConfig;
|
||||
import sun.java2d.pipe.hw.AccelTypedVolatileImage;
|
||||
import sun.java2d.pipe.hw.ContextCapabilities;
|
||||
|
||||
public interface VKGraphicsConfig extends AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig {
|
||||
boolean isCapPresent(int capsExtGradShader);
|
||||
import java.awt.BufferCapabilities;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.ImageCapabilities;
|
||||
|
||||
import static java.awt.Transparency.OPAQUE;
|
||||
import static java.awt.Transparency.TRANSLUCENT;
|
||||
import static sun.java2d.pipe.hw.AccelSurface.RT_TEXTURE;
|
||||
import static sun.java2d.pipe.hw.AccelSurface.TEXTURE;
|
||||
|
||||
/**
|
||||
* Base type for Vulkan graphics config.
|
||||
* Despite it being an interface, it contains a (preferred) default implementation
|
||||
* for most of the methods, including base methods of GraphicsConfiguration class.
|
||||
*/
|
||||
public interface VKGraphicsConfig extends AccelGraphicsConfig,
|
||||
SurfaceManager.ProxiedGraphicsConfig {
|
||||
|
||||
default VolatileSurfaceManager createVolatileManager(SunVolatileImage image,
|
||||
Object context) {
|
||||
return new VKVolatileSurfaceManager(image, context);
|
||||
}
|
||||
|
||||
VKGraphicsConfig getOffscreenConfig();
|
||||
|
||||
default VKGPU getGPU() {
|
||||
return getOffscreenConfig().getGPU();
|
||||
}
|
||||
|
||||
default VKFormat getFormat() {
|
||||
return getOffscreenConfig().getFormat();
|
||||
}
|
||||
|
||||
default double getScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
default SurfaceManager.ProxyCache getSurfaceDataProxyCache() {
|
||||
return getGPU().getSurfaceDataProxyCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BufferedContext getContext() {
|
||||
return VKContext.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provided capability bit is present for this config.
|
||||
* See VKContext.java for a list of supported capabilities.
|
||||
*/
|
||||
default boolean isCapPresent(int cap) { // TODO refactor capability checks.
|
||||
return ((getContextCapabilities().getCaps() & cap) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
default ContextCapabilities getContextCapabilities() {
|
||||
return VKContext.VKContextCaps.CONTEXT_CAPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
default VolatileImage createCompatibleVolatileImage(int width, int height, int transparency, int type) {
|
||||
if (type != RT_TEXTURE && type != TEXTURE) return null;
|
||||
if (transparency != OPAQUE && (transparency != TRANSLUCENT || !isTranslucencyCapable())) return null;
|
||||
SunVolatileImage vi =
|
||||
new AccelTypedVolatileImage((GraphicsConfiguration) this, width, height, transparency, type);
|
||||
Surface sd = vi.getDestSurface();
|
||||
if (!(sd instanceof VKSurfaceData vsd) || vsd.getType() != type) {
|
||||
vi.flush();
|
||||
vi = null;
|
||||
}
|
||||
return vi;
|
||||
}
|
||||
|
||||
default String descriptorString() {
|
||||
return getFormat().name() + ", " + getGPU();
|
||||
}
|
||||
|
||||
// Default implementation of GraphicsConfiguration methods.
|
||||
// Those need to be explicitly overridden by subclasses using VKGraphicsConfig.super.
|
||||
|
||||
default BufferedImage createCompatibleImage(int width, int height) {
|
||||
return createCompatibleImage(width, height, isTranslucencyCapable() ? TRANSLUCENT : OPAQUE);
|
||||
}
|
||||
|
||||
default BufferedImage createCompatibleImage(int width, int height, int transparency) {
|
||||
return getFormat().createCompatibleImage(width, height, transparency);
|
||||
}
|
||||
|
||||
default ColorModel getColorModel() {
|
||||
return getColorModel(isTranslucencyCapable() ? TRANSLUCENT : OPAQUE);
|
||||
}
|
||||
|
||||
default ColorModel getColorModel(int transparency) {
|
||||
return getFormat().getFormatModel(transparency).getColorModel();
|
||||
}
|
||||
|
||||
default BufferCapabilities getBufferCapabilities() {
|
||||
return VKContext.VKContextCaps.BUFFER_CAPS;
|
||||
}
|
||||
|
||||
default ImageCapabilities getImageCapabilities() {
|
||||
return VKContext.VKContextCaps.IMAGE_CAPS;
|
||||
}
|
||||
|
||||
default boolean isTranslucencyCapable() {
|
||||
return getFormat().isTranslucencyCapable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
public class VKInstance {
|
||||
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.java2d.vulkan.VKInstance");
|
||||
private static Boolean initialized;
|
||||
private static Boolean sdAccelerated;
|
||||
|
||||
private static native boolean initNative(long nativePtr, boolean verbose, int deviceNumber);
|
||||
|
||||
public static void init(long nativePtr) {
|
||||
@SuppressWarnings("removal")
|
||||
String vulkanOption = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan", ""));
|
||||
if ("true".equalsIgnoreCase(vulkanOption)) {
|
||||
@SuppressWarnings("removal")
|
||||
String deviceNumberOption = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.deviceNumber", "0"));
|
||||
int parsedDeviceNumber = 0;
|
||||
try {
|
||||
parsedDeviceNumber = Integer.parseInt(deviceNumberOption);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warning("Invalid Vulkan device number:" + deviceNumberOption);
|
||||
}
|
||||
final int deviceNumber = parsedDeviceNumber;
|
||||
final boolean verbose = "True".equals(vulkanOption);
|
||||
System.loadLibrary("awt");
|
||||
@SuppressWarnings("removal")
|
||||
String sdOption = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty("sun.java2d.vulkan.accelsd", ""));
|
||||
initialized = initNative(nativePtr, verbose, deviceNumber);
|
||||
sdAccelerated = initialized && "true".equalsIgnoreCase(sdOption);
|
||||
} else initialized = false;
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Vulkan rendering enabled: " + (initialized ? "YES" : "NO"));
|
||||
log.fine("Vulkan accelerated surface data enabled: " + (sdAccelerated ? "YES" : "NO"));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isVulkanEnabled() {
|
||||
if (initialized == null) throw new RuntimeException("Vulkan not initialized");
|
||||
return initialized;
|
||||
}
|
||||
|
||||
public static boolean isSurfaceDataAccelerated() {
|
||||
if (initialized == null) throw new RuntimeException("Vulkan not initialized");
|
||||
return sdAccelerated;
|
||||
}
|
||||
}
|
||||
@@ -25,26 +25,28 @@
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.VolatileImage;
|
||||
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
|
||||
/**
|
||||
* SurfaceData object representing an off-screen buffer
|
||||
*/
|
||||
public class VKOffScreenSurfaceData extends VKSurfaceData {
|
||||
private final Image offscreenImage;
|
||||
private native void initOps(int width, int height);
|
||||
|
||||
public VKOffScreenSurfaceData(VKGraphicsConfig gc, Image image, ColorModel cm,
|
||||
int type, int width, int height)
|
||||
{
|
||||
super(gc, cm, type, width, height);
|
||||
private final Image offscreenImage;
|
||||
private final int userWidth, userHeight; // In logical units.
|
||||
|
||||
private native void initOps(int format);
|
||||
|
||||
public VKOffScreenSurfaceData(Image image, VKFormat format, int transparency, int type, int width, int height) {
|
||||
super(format, transparency, type);
|
||||
this.userWidth = width;
|
||||
this.userHeight = height;
|
||||
offscreenImage = image;
|
||||
initOps(width, height);
|
||||
initOps(format.getValue(transparency));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,11 +54,6 @@ public class VKOffScreenSurfaceData extends VKSurfaceData {
|
||||
return restoreContents(offscreenImage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNativeResource(int resType) {
|
||||
return 0;
|
||||
@@ -76,13 +73,13 @@ public class VKOffScreenSurfaceData extends VKSurfaceData {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedContext getContext() {
|
||||
return getGraphicsConfig().getContext();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isOnScreen() {
|
||||
return false;
|
||||
protected int revalidate(VKGraphicsConfig gc) {
|
||||
int result = super.revalidate(gc);
|
||||
if (result != VolatileImage.IMAGE_INCOMPATIBLE) {
|
||||
scale = gc.getScale();
|
||||
width = (int) Math.ceil(scale * userWidth);
|
||||
height = (int) Math.ceil(scale * userHeight);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import java.awt.BufferCapabilities;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
|
||||
public class VKOffscreenGraphicsConfig extends GraphicsConfiguration implements VKGraphicsConfig {
|
||||
private final VKOffsecreenGraphicsDevice graphicsDevice = new VKOffsecreenGraphicsDevice(this);
|
||||
private final VKGPU gpu;
|
||||
private final VKFormat format;
|
||||
|
||||
VKOffscreenGraphicsConfig(VKGPU gpu, VKFormat format) {
|
||||
this.gpu = gpu;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsDevice getDevice() {
|
||||
return graphicsDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VKGraphicsConfig getOffscreenConfig() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VKGPU getGPU() {
|
||||
return gpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VKFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getDefaultTransform() {
|
||||
return new AffineTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getNormalizingTransform() {
|
||||
return new AffineTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return new Rectangle(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage createCompatibleImage(int width, int height) {
|
||||
return VKGraphicsConfig.super.createCompatibleImage(width, height);
|
||||
}
|
||||
@Override
|
||||
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
|
||||
return VKGraphicsConfig.super.createCompatibleImage(width, height, transparency);
|
||||
}
|
||||
@Override
|
||||
public ColorModel getColorModel() {
|
||||
return VKGraphicsConfig.super.getColorModel();
|
||||
}
|
||||
@Override
|
||||
public ColorModel getColorModel(int transparency) {
|
||||
return VKGraphicsConfig.super.getColorModel(transparency);
|
||||
}
|
||||
@Override
|
||||
public BufferCapabilities getBufferCapabilities() {
|
||||
return VKGraphicsConfig.super.getBufferCapabilities();
|
||||
}
|
||||
@Override
|
||||
public ImageCapabilities getImageCapabilities() {
|
||||
return VKGraphicsConfig.super.getImageCapabilities();
|
||||
}
|
||||
@Override
|
||||
public boolean isTranslucencyCapable() {
|
||||
return VKGraphicsConfig.super.isTranslucencyCapable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VKOffscreenGraphicsConfig[" + descriptorString() + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.java2d.vulkan;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
|
||||
public class VKOffsecreenGraphicsDevice extends GraphicsDevice {
|
||||
|
||||
private final VKGraphicsConfig config;
|
||||
|
||||
VKOffsecreenGraphicsDevice(VKGraphicsConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return GraphicsDevice.TYPE_IMAGE_BUFFER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIDstring() {
|
||||
return "VKOffscreenGraphicsDevice";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration[] getConfigurations() {
|
||||
return new GraphicsConfiguration[]{ getDefaultConfiguration() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration getDefaultConfiguration() {
|
||||
return (GraphicsConfiguration) config;
|
||||
}
|
||||
}
|
||||
@@ -31,19 +31,24 @@ import sun.awt.SunHints;
|
||||
import sun.awt.image.PixelConverter;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.loops.Blit;
|
||||
import sun.java2d.loops.CompositeType;
|
||||
import sun.java2d.loops.GraphicsPrimitive;
|
||||
import sun.java2d.loops.SurfaceType;
|
||||
import static sun.java2d.pipe.BufferedOpCodes.CONFIGURE_SURFACE;
|
||||
import sun.java2d.pipe.BufferedContext;
|
||||
import sun.java2d.pipe.ParallelogramPipe;
|
||||
import sun.java2d.pipe.PixelToParallelogramConverter;
|
||||
import sun.java2d.pipe.RenderBuffer;
|
||||
import sun.java2d.pipe.TextPipe;
|
||||
import sun.java2d.pipe.hw.AccelSurface;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.VolatileImage;
|
||||
|
||||
import static sun.java2d.pipe.BufferedOpCodes.FLUSH_SURFACE;
|
||||
import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
|
||||
|
||||
@@ -51,40 +56,9 @@ import static sun.java2d.pipe.hw.ContextCapabilities.CAPS_PS30;
|
||||
public abstract class VKSurfaceData extends SurfaceData
|
||||
implements AccelSurface {
|
||||
|
||||
/**
|
||||
* Pixel formats
|
||||
*/
|
||||
public static final int PF_INT_ARGB = 0;
|
||||
public static final int PF_INT_ARGB_PRE = 1;
|
||||
public static final int PF_INT_RGB = 2;
|
||||
public static final int PF_INT_RGBX = 3;
|
||||
public static final int PF_INT_BGR = 4;
|
||||
public static final int PF_INT_BGRX = 5;
|
||||
public static final int PF_USHORT_565_RGB = 6;
|
||||
public static final int PF_USHORT_555_RGB = 7;
|
||||
public static final int PF_USHORT_555_RGBX = 8;
|
||||
public static final int PF_BYTE_GRAY = 9;
|
||||
public static final int PF_USHORT_GRAY = 10;
|
||||
public static final int PF_3BYTE_BGR = 11;
|
||||
/**
|
||||
* SurfaceTypes
|
||||
*/
|
||||
|
||||
private static final String DESC_VK_SURFACE = "VK Surface";
|
||||
private static final String DESC_VK_SURFACE_RTT =
|
||||
"VK Surface (render-to-texture)";
|
||||
private static final String DESC_VK_TEXTURE = "VK Texture";
|
||||
|
||||
|
||||
// We want non-premultiplied alpha to prevent precision loss, so use PixelConverter.Argb
|
||||
// See also VKUtil_DecodeJavaColor.
|
||||
static final SurfaceType VKSurface =
|
||||
SurfaceType.Any.deriveSubType(DESC_VK_SURFACE,
|
||||
PixelConverter.Argb.instance);
|
||||
static final SurfaceType VKSurfaceRTT =
|
||||
VKSurface.deriveSubType(DESC_VK_SURFACE_RTT);
|
||||
static final SurfaceType VKTexture =
|
||||
SurfaceType.Any.deriveSubType(DESC_VK_TEXTURE);
|
||||
static final SurfaceType VKSurface = SurfaceType.Any.deriveSubType("VK Surface", PixelConverter.Argb.instance);
|
||||
|
||||
protected static VKRenderer vkRenderPipe;
|
||||
protected static PixelToParallelogramConverter vkTxRenderPipe;
|
||||
@@ -93,74 +67,59 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
protected static VKDrawImage vkImagePipe;
|
||||
|
||||
static {
|
||||
if (!GraphicsEnvironment.isHeadless()) {
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
vkImagePipe = new VKDrawImage();
|
||||
vkTextPipe = new VKTextRenderer(rq);
|
||||
vkRenderPipe = new VKRenderer(rq);
|
||||
if (GraphicsPrimitive.tracingEnabled()) {
|
||||
vkTextPipe = vkTextPipe.traceWrap();
|
||||
//The wrapped vkRenderPipe will wrap the AA pipe as well...
|
||||
vkAAPgramPipe = vkRenderPipe.traceWrap();
|
||||
}
|
||||
vkAAPgramPipe = vkRenderPipe.getAAParallelogramPipe();
|
||||
vkTxRenderPipe =
|
||||
new PixelToParallelogramConverter(vkRenderPipe, vkRenderPipe, 1.0, 0.25, true);
|
||||
|
||||
VKBlitLoops.register();
|
||||
VKMaskFill.register();
|
||||
VKMaskBlit.register();
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
vkImagePipe = new VKDrawImage();
|
||||
vkTextPipe = new VKTextRenderer(rq);
|
||||
vkRenderPipe = new VKRenderer(rq);
|
||||
if (GraphicsPrimitive.tracingEnabled()) {
|
||||
vkTextPipe = vkTextPipe.traceWrap();
|
||||
//The wrapped vkRenderPipe will wrap the AA pipe as well...
|
||||
vkAAPgramPipe = vkRenderPipe.traceWrap();
|
||||
}
|
||||
vkAAPgramPipe = vkRenderPipe.getAAParallelogramPipe();
|
||||
vkTxRenderPipe = new PixelToParallelogramConverter(vkRenderPipe, vkRenderPipe, 1.0, 0.25, true);
|
||||
}
|
||||
|
||||
// TODO Do we really want to have scale there? It is used by getDefaultScaleX/Y...
|
||||
protected int scale;
|
||||
private final VKFormat format;
|
||||
protected VKGraphicsConfig gc;
|
||||
protected double scale;
|
||||
protected int width;
|
||||
protected int height;
|
||||
protected int type;
|
||||
private VKGraphicsConfig graphicsConfig;
|
||||
// these fields are set from the native code when the surface is
|
||||
// initialized
|
||||
private int nativeWidth;
|
||||
private int nativeHeight;
|
||||
private int type;
|
||||
|
||||
/**
|
||||
* Returns the appropriate SurfaceType corresponding to the given Metal
|
||||
* surface type constant (e.g. TEXTURE -> MTLTexture).
|
||||
*/
|
||||
private static SurfaceType getCustomSurfaceType(int vkType) {
|
||||
switch (vkType) {
|
||||
case TEXTURE:
|
||||
return VKTexture;
|
||||
case RT_TEXTURE:
|
||||
return VKSurfaceRTT;
|
||||
default:
|
||||
return VKSurface;
|
||||
}
|
||||
}
|
||||
|
||||
protected VKSurfaceData(VKGraphicsConfig gc, ColorModel cm, int type, int width, int height)
|
||||
{
|
||||
super(getCustomSurfaceType(type), cm);
|
||||
this.graphicsConfig = gc;
|
||||
protected VKSurfaceData(VKFormat format, int transparency, int type) {
|
||||
super(format.getSurfaceType(transparency), format.getFormatModel(transparency).getColorModel());
|
||||
this.format = format;
|
||||
this.type = type;
|
||||
setBlitProxyCache(gc.getSurfaceDataProxyCache());
|
||||
|
||||
// TEXTURE shouldn't be scaled, it is used for managed BufferedImages.
|
||||
scale = 1;
|
||||
this.width = width * scale;
|
||||
this.height = height * scale;
|
||||
}
|
||||
|
||||
public VKFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultScaleX() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultScaleY() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of the surface type constants defined above.
|
||||
*/
|
||||
@Override
|
||||
public final int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
return (GraphicsConfiguration) gc;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
invalidate();
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
@@ -178,28 +137,28 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
throw new InternalError("not implemented yet");
|
||||
protected BufferedImage getSnapshot(int x, int y, int width, int height) {
|
||||
BufferedImage image = getFormat().createCompatibleImage(width, height, getTransparency());
|
||||
SurfaceData sd = SurfaceData.getPrimarySurfaceData(image);
|
||||
Blit blit = Blit.getFromCache(getSurfaceType(), CompositeType.SrcNoEa, sd.getSurfaceType());
|
||||
blit.Blit(this, sd, AlphaComposite.Src, null, x, y, 0, 0, width, height);
|
||||
return image;
|
||||
}
|
||||
|
||||
public Raster getRaster(int x, int y, int w, int h) {
|
||||
return getSnapshot(x, y, w, h).getRaster().createTranslatedChild(x, y);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Rectangle getNativeBounds() {
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
return new Rectangle(nativeWidth, nativeHeight);
|
||||
} finally {
|
||||
rq.unlock();
|
||||
}
|
||||
return new Rectangle(width, height);
|
||||
}
|
||||
|
||||
public void validatePipe(SunGraphics2D sg2d) {
|
||||
TextPipe textpipe;
|
||||
boolean validated = false;
|
||||
|
||||
// MTLTextRenderer handles both AA and non-AA text, but
|
||||
// VKTextRenderer handles both AA and non-AA text, but
|
||||
// only works with the following modes:
|
||||
// (Note: For LCD text we only enter this code path if
|
||||
// canRenderLCDText() has already validated that the mode is
|
||||
@@ -247,7 +206,7 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
}
|
||||
} else {
|
||||
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
|
||||
if (graphicsConfig.isCapPresent(CAPS_PS30) &&
|
||||
if (getGraphicsConfig().isCapPresent(CAPS_PS30) &&
|
||||
(sg2d.imageComp == CompositeType.SrcOverNoEa ||
|
||||
sg2d.imageComp == CompositeType.SrcOver))
|
||||
{
|
||||
@@ -300,18 +259,29 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
sg2d.imagepipe = vkImagePipe;
|
||||
}
|
||||
|
||||
// TODO this is only used for caps checks, refactor and remove this method
|
||||
public VKGraphicsConfig getGraphicsConfig() {
|
||||
return graphicsConfig;
|
||||
return (VKGraphicsConfig) getDeviceConfiguration();
|
||||
}
|
||||
|
||||
protected synchronized void configure() {
|
||||
protected int revalidate(VKGraphicsConfig gc) {
|
||||
if (gc.getFormat() != format) return VolatileImage.IMAGE_INCOMPATIBLE;
|
||||
else if (this.gc == gc) return VolatileImage.IMAGE_OK;
|
||||
// TODO proxy cache needs to be cleared for this surface data?
|
||||
setBlitProxyCache(gc.getGPU().getSurfaceDataProxyCache());
|
||||
this.gc = gc;
|
||||
return VolatileImage.IMAGE_RESTORED;
|
||||
}
|
||||
|
||||
protected void configure() {
|
||||
VKRenderQueue rq = VKRenderQueue.getInstance();
|
||||
rq.lock();
|
||||
try {
|
||||
RenderBuffer buf = rq.getBuffer();
|
||||
rq.ensureCapacityAndAlignment(20, 4);
|
||||
rq.ensureCapacityAndAlignment(24, 4);
|
||||
buf.putInt(CONFIGURE_SURFACE);
|
||||
buf.putLong(getNativeOps());
|
||||
buf.putLong(gc.getGPU().getNativeHandle());
|
||||
buf.putInt(width);
|
||||
buf.putInt(height);
|
||||
|
||||
@@ -321,5 +291,8 @@ public abstract class VKSurfaceData extends SurfaceData
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean isOnScreen();
|
||||
@Override
|
||||
public BufferedContext getContext() {
|
||||
return VKContext.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* Copyright 2025 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -29,17 +28,17 @@ package sun.java2d.vulkan;
|
||||
import sun.awt.image.SunVolatileImage;
|
||||
import sun.awt.image.VolatileSurfaceManager;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.java2d.pipe.hw.AccelSurface;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.image.ColorModel;
|
||||
import sun.java2d.pipe.hw.AccelSurface;
|
||||
import java.awt.image.VolatileImage;
|
||||
|
||||
public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
|
||||
public class VKVolatileSurfaceManager extends VolatileSurfaceManager {
|
||||
|
||||
private final boolean accelerationEnabled;
|
||||
|
||||
public WLVKVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
|
||||
public VKVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
|
||||
super(vImg, context);
|
||||
|
||||
/*
|
||||
@@ -48,7 +47,7 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
|
||||
*/
|
||||
int transparency = vImg.getTransparency();
|
||||
|
||||
accelerationEnabled = VKInstance.isSurfaceDataAccelerated() &&
|
||||
accelerationEnabled = VKEnv.isSurfaceDataAccelerated() &&
|
||||
transparency != Transparency.BITMASK;
|
||||
}
|
||||
|
||||
@@ -62,25 +61,43 @@ public class WLVKVolatileSurfaceManager extends VolatileSurfaceManager {
|
||||
*/
|
||||
protected SurfaceData initAcceleratedSurface() {
|
||||
try {
|
||||
WLVKGraphicsConfig gc =
|
||||
(WLVKGraphicsConfig)vImg.getGraphicsConfig();
|
||||
ColorModel cm = gc.getColorModel(vImg.getTransparency());
|
||||
VKGraphicsConfig gc = (VKGraphicsConfig) vImg.getGraphicsConfig();
|
||||
int type = vImg.getForcedAccelSurfaceType();
|
||||
// if acceleration type is forced (type != UNDEFINED) then
|
||||
// use the forced type, otherwise choose RT_TEXTURE
|
||||
if (type == AccelSurface.UNDEFINED) {
|
||||
type = AccelSurface.RT_TEXTURE;
|
||||
}
|
||||
return new VKOffScreenSurfaceData(
|
||||
gc, vImg, cm, type, vImg.getWidth(), vImg.getHeight());
|
||||
VKOffScreenSurfaceData sd = new VKOffScreenSurfaceData(vImg, gc.getFormat(), vImg.getTransparency(), type,
|
||||
vImg.getWidth(), vImg.getHeight());
|
||||
sd.revalidate(gc);
|
||||
sd.configure();
|
||||
return sd;
|
||||
} catch (NullPointerException | OutOfMemoryError ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int validate(GraphicsConfiguration gc) {
|
||||
if (gc != null && sdAccel != null && isAccelerationEnabled() && isConfigValid(gc)) {
|
||||
VKSurfaceData vksd = (VKSurfaceData) sdAccel;
|
||||
switch (vksd.revalidate((VKGraphicsConfig) gc)) {
|
||||
case VolatileImage.IMAGE_INCOMPATIBLE:
|
||||
return VolatileImage.IMAGE_INCOMPATIBLE;
|
||||
case VolatileImage.IMAGE_RESTORED:
|
||||
vksd.setSurfaceLost(true);
|
||||
vksd.configure();
|
||||
}
|
||||
}
|
||||
return super.validate(gc);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConfigValid(GraphicsConfiguration gc) {
|
||||
return ((gc == null) || (gc == vImg.getGraphicsConfig()));
|
||||
// We consider configs with the same format compatible across Vulkan devices.
|
||||
return gc == null || vImg.getGraphicsConfig() == null ||
|
||||
((VKGraphicsConfig) gc).getFormat() == ((VKGraphicsConfig) vImg.getGraphicsConfig()).getFormat();
|
||||
}
|
||||
|
||||
@Override
|
||||
20
src/java.desktop/share/glsl/vulkan/alpha_type.glsl
Normal file
20
src/java.desktop/share/glsl/vulkan/alpha_type.glsl
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
#define ALPHA_TYPE_PRE_MULTIPLIED 0U
|
||||
#define ALPHA_TYPE_STRAIGHT 1U
|
||||
|
||||
vec4 convertAlpha(vec4 color, uint inType, uint outType) {
|
||||
if (inType == ALPHA_TYPE_STRAIGHT && outType == ALPHA_TYPE_PRE_MULTIPLIED) {
|
||||
return vec4(color.rgb * color.a, color.a);
|
||||
} else if (inType == ALPHA_TYPE_PRE_MULTIPLIED && outType == ALPHA_TYPE_STRAIGHT && color.a > 0.0) {
|
||||
return vec4(color.rgb / color.a, color.a);
|
||||
} else return color;
|
||||
}
|
||||
|
||||
#ifdef ALPHA_TYPE_SPEC_INDEX
|
||||
layout (constant_id = ALPHA_TYPE_SPEC_INDEX ) const uint const_InAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
layout (constant_id = ALPHA_TYPE_SPEC_INDEX+1) const uint const_OutAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
|
||||
vec4 convertAlpha(vec4 color) {
|
||||
return convertAlpha(color, const_InAlphaType, const_OutAlphaType);
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +1,13 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive: require
|
||||
#define ALPHA_TYPE_SPEC_INDEX 0
|
||||
#include "alpha_type.glsl"
|
||||
|
||||
layout(binding = 0) uniform sampler2D u_TexSampler;
|
||||
layout(set = 0, binding = 0) uniform texture2D u_Texture;
|
||||
layout(set = 1, binding = 0) uniform sampler u_Sampler;
|
||||
layout(location = 0) in vec2 in_TexCoord;
|
||||
layout(location = 0) out vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
out_Color = texture(u_TexSampler, in_TexCoord);
|
||||
// TODO: Temporary fix of unexpected transparency with blit operations
|
||||
out_Color.a = 1.0;
|
||||
out_Color = convertAlpha(texture(sampler2D(u_Texture, u_Sampler), in_TexCoord));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 viewportNormalizer; // 2.0 / viewport
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec2 in_Position;
|
||||
@@ -9,6 +9,6 @@ layout(location = 1) in vec2 in_TexCoord;
|
||||
layout(location = 0) out vec2 out_TexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(in_Position * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
|
||||
gl_Position = vec4(vec3(in_Position, 1.0)*push.transform, 0.0, 1.0);
|
||||
out_TexCoord = in_TexCoord;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 viewportNormalizer; // 2.0 / viewport
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in ivec2 in_Position;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vec2(in_Position) * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
|
||||
gl_Position = vec4(vec3(in_Position, 1)*push.transform, 0.0, 1.0);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 viewportNormalizer; // 2.0 / viewport
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec2 in_Position;
|
||||
@@ -9,6 +9,6 @@ layout(location = 1) in vec4 in_Color;
|
||||
layout(location = 0) out flat vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(in_Position * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
|
||||
gl_Position = vec4(vec3(in_Position, 1)*push.transform, 0.0, 1.0);
|
||||
out_Color = in_Color;
|
||||
}
|
||||
@@ -10,7 +10,7 @@ layout(location = 1) in flat vec4 in_Color;
|
||||
layout(location = 0) out vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
ivec2 maskPos = ivec2(gl_FragCoord.xy) - in_OriginOffsetAndScanline.xy;
|
||||
ivec2 maskPos = ivec2(gl_FragCoord.xy - vec2(in_OriginOffsetAndScanline.xy));
|
||||
int offset = in_OriginOffsetAndScanline.z;
|
||||
int scanline = in_OriginOffsetAndScanline.w;
|
||||
int maskIndex = offset + scanline * maskPos.y + min(scanline, maskPos.x);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
vec2 viewportNormalizer; // 2.0 / viewport
|
||||
mat2x3 transform;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in ivec4 in_PositionOffsetAndScanline;
|
||||
@@ -14,7 +14,7 @@ layout(location = 0) out flat ivec4 out_OriginOffsetAndScanline;
|
||||
layout(location = 1) out flat vec4 out_Color;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vec2(in_PositionOffsetAndScanline.xy) * push.viewportNormalizer - vec2(1.0), 0.0, 1.0);
|
||||
gl_Position = vec4(vec3(in_PositionOffsetAndScanline.xy, 1)*push.transform, 0.0, 1.0);
|
||||
out_OriginOffsetAndScanline = in_PositionOffsetAndScanline;
|
||||
out_Color = in_Color;
|
||||
}
|
||||
@@ -432,22 +432,22 @@ bool CARR_hash_map_linear_probing_rehash(CARR_MAP_LAYOUT_ARGS, void** handle, CA
|
||||
/**
|
||||
* Find a value for the provided key.
|
||||
* @param P map
|
||||
* @param KEY key to find, can be a compound literal, like (int){0}
|
||||
* @param ... key to find, can be a compound literal, like (int){0}
|
||||
* @return pointer to the found value, or NULL
|
||||
*/
|
||||
#define MAP_FIND(P, KEY) \
|
||||
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(KEY)), NULL, false))
|
||||
#define MAP_FIND(P, ...) \
|
||||
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(__VA_ARGS__)), NULL, false))
|
||||
|
||||
/**
|
||||
* Find a value for the provided key, or insert a new one.
|
||||
* Value is zeroed for newly inserted items.
|
||||
* On allocation failure, C_ARRAY_UTIL_ALLOCATION_FAILED is called.
|
||||
* @param P map
|
||||
* @param KEY key to find, can be a compound literal, like (int){0}
|
||||
* @param ... key to find, can be a compound literal, like (int){0}
|
||||
* @return dereferenced pointer to the found value
|
||||
*/
|
||||
#define MAP_AT(P, KEY) (*(MAP_ENSURE_EXTRA_CAPACITY((P), 1), \
|
||||
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(KEY)), NULL, true))))
|
||||
#define MAP_AT(P, ...) (*(MAP_ENSURE_EXTRA_CAPACITY((P), 1), \
|
||||
CARR_MAP_VALUE_PTR((P), CARR_MAP_DISPATCH((P), find, (P), CARR_MAP_KEY_GUARD((P), &(__VA_ARGS__)), NULL, true))))
|
||||
|
||||
/**
|
||||
* Resolve provided key and find corresponding value.
|
||||
@@ -474,10 +474,10 @@ bool CARR_hash_map_linear_probing_rehash(CARR_MAP_LAYOUT_ARGS, void** handle, CA
|
||||
/**
|
||||
* Remove the provided key, if one exists.
|
||||
* @param P map
|
||||
* @param KEY key to remove, can be a compound literal, like (int){0}
|
||||
* @param ... key to remove, can be a compound literal, like (int){0}
|
||||
* @return true if the key was removed
|
||||
*/
|
||||
#define MAP_REMOVE(P, KEY) CARR_MAP_DISPATCH((P), remove, (P), CARR_MAP_KEY_GUARD((P), &(KEY)))
|
||||
#define MAP_REMOVE(P, ...) CARR_MAP_DISPATCH((P), remove, (P), CARR_MAP_KEY_GUARD((P), &(__VA_ARGS__)))
|
||||
|
||||
/**
|
||||
* Ensure that map has enough capacity to insert COUNT more items without reallocation.
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKEnv.h"
|
||||
|
||||
/**
|
||||
* Block size is a minimum allocation size.
|
||||
@@ -165,9 +165,11 @@ VKMemoryRequirements VKAllocator_ImageRequirements(VKAllocator* allocator, VkIma
|
||||
return r;
|
||||
}
|
||||
|
||||
void VKAllocator_PadToAlignment(VKMemoryRequirements* requirements) {
|
||||
void VKAllocator_PadToAlignment(VKAllocator* allocator, VKMemoryRequirements* requirements) {
|
||||
assert(allocator != NULL);
|
||||
assert(requirements != NULL);
|
||||
VkMemoryRequirements* t = &requirements->requirements.memoryRequirements;
|
||||
if (t->alignment < allocator->device->nonCoherentAtomSize) t->alignment = allocator->device->nonCoherentAtomSize;
|
||||
t->size = ((t->size + t->alignment - 1) / t->alignment) * t->alignment;
|
||||
requirements->dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE;
|
||||
requirements->dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE;
|
||||
@@ -562,8 +564,7 @@ void VKAllocator_Invalidate(VKAllocator* allocator, VKMemory memory, VkDeviceSiz
|
||||
}
|
||||
|
||||
VKAllocator* VKAllocator_Create(VKDevice* device) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKAllocator* allocator = (VKAllocator*) calloc(1, sizeof(VKAllocator));
|
||||
VKAllocator* allocator = calloc(1, sizeof(VKAllocator));
|
||||
allocator->device = device;
|
||||
allocator->freePageIndex = NO_PAGE_INDEX;
|
||||
for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
|
||||
@@ -572,7 +573,7 @@ VKAllocator* VKAllocator_Create(VKDevice* device) {
|
||||
.allocationLevelTracker = MIN_SHARED_PAGE_LEVEL * 2
|
||||
};
|
||||
}
|
||||
ge->vkGetPhysicalDeviceMemoryProperties(device->physicalDevice, &allocator->memoryProperties);
|
||||
VKEnv_GetInstance()->vkGetPhysicalDeviceMemoryProperties(device->physicalDevice, &allocator->memoryProperties);
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKAllocator_Create: allocator=%p", allocator);
|
||||
return allocator;
|
||||
|
||||
@@ -62,7 +62,7 @@ VKMemoryRequirements VKAllocator_ImageRequirements(VKAllocator* allocator, VkIma
|
||||
* This also resets dedicated requirement flags, as for dedicated allocations size must
|
||||
* be strictly equal to the one returned by resource memory requirements.
|
||||
*/
|
||||
void VKAllocator_PadToAlignment(VKMemoryRequirements* requirements);
|
||||
void VKAllocator_PadToAlignment(VKAllocator* allocator, VKMemoryRequirements* requirements);
|
||||
|
||||
/**
|
||||
* Find memory type with properties not less than requiredProperties and not more than allowedProperties,
|
||||
|
||||
@@ -1,730 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKTexturePool.h"
|
||||
|
||||
// For old Vulkan headers - define version-related macros.
|
||||
#ifndef VK_MAKE_API_VERSION
|
||||
# define VK_MAKE_API_VERSION(variant, major, minor, patch) VK_MAKE_VERSION(major, minor, patch)
|
||||
# define VK_API_VERSION_MAJOR(version) VK_VERSION_MAJOR(version)
|
||||
# define VK_API_VERSION_MINOR(version) VK_VERSION_MINOR(version)
|
||||
# define VK_API_VERSION_PATCH(version) VK_VERSION_PATCH(version)
|
||||
#endif
|
||||
|
||||
#define VULKAN_DLL JNI_LIB_NAME("vulkan")
|
||||
#define VULKAN_1_DLL VERSIONED_JNI_LIB_NAME("vulkan", "1")
|
||||
static const uint32_t REQUIRED_VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 2, 0);
|
||||
|
||||
#define VALIDATION_LAYER_NAME "VK_LAYER_KHRONOS_validation"
|
||||
|
||||
static jboolean verbose;
|
||||
static VKGraphicsEnvironment* geInstance = NULL;
|
||||
static void* pVulkanLib = NULL;
|
||||
|
||||
#define GET_VK_PROC_RET_FALSE_IF_ERR(GETPROCADDR, STRUCT, HANDLE, NAME) do { \
|
||||
(STRUCT)->NAME = (PFN_ ## NAME) GETPROCADDR(HANDLE, #NAME); \
|
||||
if ((STRUCT)->NAME == NULL) { \
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Required api is not supported. " #NAME " is missing.") \
|
||||
return JNI_FALSE; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void vulkanLibClose() {
|
||||
if (pVulkanLib != NULL) {
|
||||
if (geInstance != NULL) {
|
||||
ARRAY_FREE(geInstance->physicalDevices);
|
||||
if (geInstance->devices != NULL) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(geInstance->devices); i++) {
|
||||
VKDevice* device = &geInstance->devices[i];
|
||||
VKRenderer_Destroy(device->renderer);
|
||||
VKTexturePool_Dispose(device->texturePool);
|
||||
VKAllocator_Destroy(device->allocator);
|
||||
ARRAY_FREE(device->enabledExtensions);
|
||||
ARRAY_FREE(device->enabledLayers);
|
||||
free(device->name);
|
||||
if (device->vkDestroyDevice != NULL) {
|
||||
device->vkDestroyDevice(device->handle, NULL);
|
||||
}
|
||||
}
|
||||
ARRAY_FREE(geInstance->devices);
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
if (geInstance->vkDestroyDebugUtilsMessengerEXT != NULL && geInstance->vkInstance != VK_NULL_HANDLE) {
|
||||
geInstance->vkDestroyDebugUtilsMessengerEXT(geInstance->vkInstance, geInstance->debugMessenger, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
VKComposites_Destroy(geInstance->composites);
|
||||
|
||||
if (geInstance->vkDestroyInstance != NULL) {
|
||||
geInstance->vkDestroyInstance(geInstance->vkInstance, NULL);
|
||||
}
|
||||
free(geInstance);
|
||||
geInstance = NULL;
|
||||
}
|
||||
dlclose(pVulkanLib);
|
||||
pVulkanLib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PFN_vkGetInstanceProcAddr vulkanLibOpen() {
|
||||
if (pVulkanLib == NULL) {
|
||||
pVulkanLib = dlopen(VULKAN_DLL, RTLD_NOW);
|
||||
if (pVulkanLib == NULL) {
|
||||
pVulkanLib = dlopen(VULKAN_1_DLL, RTLD_NOW);
|
||||
}
|
||||
if (pVulkanLib == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Vulkan: Failed to load %s", VULKAN_DLL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) dlsym(pVulkanLib, "vkGetInstanceProcAddr");
|
||||
if (vkGetInstanceProcAddr == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR,
|
||||
"Vulkan: Failed to get proc address of vkGetInstanceProcAddr from %s", VULKAN_DLL)
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
return vkGetInstanceProcAddr;
|
||||
}
|
||||
|
||||
static const char* physicalDeviceTypeString(VkPhysicalDeviceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r
|
||||
STR(OTHER);
|
||||
STR(INTEGRATED_GPU);
|
||||
STR(DISCRETE_GPU);
|
||||
STR(VIRTUAL_GPU);
|
||||
STR(CPU);
|
||||
#undef STR
|
||||
default: return "UNKNOWN_DEVICE_TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
static VkBool32 debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData
|
||||
) {
|
||||
if (pCallbackData == NULL) return VK_FALSE;
|
||||
// Here we can filter messages like this:
|
||||
// if (std::strcmp(pCallbackData->pMessageIdName, "UNASSIGNED-BestPractices-DrawState-ClearCmdBeforeDraw") == 0) return VK_FALSE;
|
||||
|
||||
int level = J2D_TRACE_OFF;
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) level = J2D_TRACE_VERBOSE;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) level = J2D_TRACE_INFO;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) level = J2D_TRACE_WARNING;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) level = J2D_TRACE_ERROR;
|
||||
|
||||
J2dRlsTraceLn(level, pCallbackData->pMessage);
|
||||
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
VK_FATAL_ERROR("Unhandled Vulkan validation error");
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static jboolean VK_InitGraphicsEnvironment(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr) {
|
||||
|
||||
geInstance->vkInstance = VK_NULL_HANDLE;
|
||||
|
||||
#define INSTANCE_PROC(NAME) GET_VK_PROC_RET_FALSE_IF_ERR(vkGetInstanceProcAddr, geInstance, geInstance->vkInstance, NAME)
|
||||
INSTANCE_PROC(vkEnumerateInstanceVersion);
|
||||
INSTANCE_PROC(vkEnumerateInstanceExtensionProperties);
|
||||
INSTANCE_PROC(vkEnumerateInstanceLayerProperties);
|
||||
INSTANCE_PROC(vkCreateInstance);
|
||||
|
||||
uint32_t apiVersion = 0;
|
||||
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceVersion(&apiVersion)) return JNI_FALSE;
|
||||
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)",
|
||||
VK_API_VERSION_MAJOR(apiVersion),
|
||||
VK_API_VERSION_MINOR(apiVersion),
|
||||
VK_API_VERSION_PATCH(apiVersion))
|
||||
|
||||
if (apiVersion < REQUIRED_VULKAN_VERSION) {
|
||||
J2dRlsTraceLn3(J2D_TRACE_ERROR, "Vulkan: Unsupported version. Required at least (%d.%d.%d)",
|
||||
VK_API_VERSION_MAJOR(REQUIRED_VULKAN_VERSION),
|
||||
VK_API_VERSION_MINOR(REQUIRED_VULKAN_VERSION),
|
||||
VK_API_VERSION_PATCH(REQUIRED_VULKAN_VERSION))
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
uint32_t extensionsCount;
|
||||
// Get the number of extensions and layers
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount, NULL)) return JNI_FALSE;
|
||||
VkExtensionProperties extensions[extensionsCount];
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceExtensionProperties(NULL, &extensionsCount, extensions)) return JNI_FALSE;
|
||||
|
||||
uint32_t layersCount;
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceLayerProperties(&layersCount, NULL)) return JNI_FALSE;
|
||||
VkLayerProperties layers[layersCount];
|
||||
VK_IF_ERROR(geInstance->vkEnumerateInstanceLayerProperties(&layersCount, layers)) return JNI_FALSE;
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported instance layers:")
|
||||
for (uint32_t i = 0; i < layersCount; i++) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) layers[i].layerName)
|
||||
}
|
||||
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported instance extensions:")
|
||||
for (uint32_t i = 0; i < extensionsCount; i++) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) extensions[i].extensionName)
|
||||
}
|
||||
|
||||
ARRAY(pchar) enabledLayers = NULL;
|
||||
ARRAY(pchar) enabledExtensions = NULL;
|
||||
void *pNext = NULL;
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
ARRAY_PUSH_BACK(enabledExtensions) = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
|
||||
#endif
|
||||
ARRAY_PUSH_BACK(enabledExtensions) = VK_KHR_SURFACE_EXTENSION_NAME;
|
||||
|
||||
// Check required layers & extensions.
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(enabledExtensions); i++) {
|
||||
int notFound = 1;
|
||||
for (uint32_t j = 0; j < extensionsCount; j++) {
|
||||
if (strcmp((char *) extensions[j].extensionName, enabledExtensions[i]) == 0) {
|
||||
notFound = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (notFound) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Vulkan: Required extension %s not found", enabledExtensions[i])
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure validation
|
||||
#ifdef DEBUG
|
||||
VkValidationFeatureEnableEXT enables[] = {
|
||||
// VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
|
||||
// VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
||||
// VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT
|
||||
};
|
||||
|
||||
VkValidationFeaturesEXT features = {};
|
||||
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
||||
features.enabledValidationFeatureCount = SARRAY_COUNT_OF(enables);
|
||||
features.pEnabledValidationFeatures = enables;
|
||||
|
||||
// Includes the validation features into the instance creation process
|
||||
|
||||
int foundDebugLayer = 0;
|
||||
for (uint32_t i = 0; i < layersCount; i++) {
|
||||
if (strcmp((char *) layers[i].layerName, VALIDATION_LAYER_NAME) == 0) {
|
||||
foundDebugLayer = 1;
|
||||
break;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) layers[i].layerName)
|
||||
}
|
||||
int foundDebugExt = 0;
|
||||
for (uint32_t i = 0; i < extensionsCount; i++) {
|
||||
if (strcmp((char *) extensions[i].extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
|
||||
foundDebugExt = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDebugLayer && foundDebugExt) {
|
||||
ARRAY_PUSH_BACK(enabledLayers) = VALIDATION_LAYER_NAME;
|
||||
ARRAY_PUSH_BACK(enabledExtensions) = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
|
||||
pNext = &features;
|
||||
} else {
|
||||
J2dRlsTraceLn2(J2D_TRACE_WARNING, "Vulkan: %s and %s are not supported",
|
||||
VALIDATION_LAYER_NAME, VK_EXT_DEBUG_UTILS_EXTENSION_NAME)
|
||||
}
|
||||
#endif
|
||||
VkApplicationInfo applicationInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pNext = NULL,
|
||||
.pApplicationName = "OpenJDK",
|
||||
.applicationVersion = 0,
|
||||
.pEngineName = "OpenJDK",
|
||||
.engineVersion = 0,
|
||||
.apiVersion = REQUIRED_VULKAN_VERSION
|
||||
};
|
||||
|
||||
VkInstanceCreateInfo instanceCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext = pNext,
|
||||
.flags = 0,
|
||||
.pApplicationInfo = &applicationInfo,
|
||||
.enabledLayerCount = ARRAY_SIZE(enabledLayers),
|
||||
.ppEnabledLayerNames = (const char *const *) enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(enabledExtensions),
|
||||
.ppEnabledExtensionNames = (const char *const *) enabledExtensions
|
||||
};
|
||||
|
||||
VK_IF_ERROR(geInstance->vkCreateInstance(&instanceCreateInfo, NULL, &geInstance->vkInstance)) {
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "Vulkan: Instance Created")
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
|
||||
geInstance->composites = VKComposites_Create();
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
|
||||
INSTANCE_PROC(vkCreateWaylandSurfaceKHR);
|
||||
#endif
|
||||
INSTANCE_PROC(vkDestroyInstance);
|
||||
INSTANCE_PROC(vkEnumeratePhysicalDevices);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceMemoryProperties);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceFeatures2);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceProperties2);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceSurfaceFormatsKHR);
|
||||
INSTANCE_PROC(vkGetPhysicalDeviceSurfacePresentModesKHR);
|
||||
INSTANCE_PROC(vkEnumerateDeviceLayerProperties);
|
||||
INSTANCE_PROC(vkEnumerateDeviceExtensionProperties);
|
||||
INSTANCE_PROC(vkCreateDevice);
|
||||
INSTANCE_PROC(vkDestroySurfaceKHR);
|
||||
INSTANCE_PROC(vkGetDeviceProcAddr);
|
||||
|
||||
// Create debug messenger
|
||||
#if defined(DEBUG)
|
||||
if (foundDebugLayer && foundDebugExt) {
|
||||
INSTANCE_PROC(vkCreateDebugUtilsMessengerEXT);
|
||||
INSTANCE_PROC(vkDestroyDebugUtilsMessengerEXT);
|
||||
if (pNext) {
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||
.flags = 0,
|
||||
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||
.pfnUserCallback = &debugCallback
|
||||
};
|
||||
VK_IF_ERROR(geInstance->vkCreateDebugUtilsMessengerEXT(geInstance->vkInstance, &debugUtilsMessengerCreateInfo,
|
||||
NULL, &geInstance->debugMessenger)) {}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jboolean VK_FindDevices() {
|
||||
uint32_t physicalDevicesCount;
|
||||
VK_IF_ERROR(geInstance->vkEnumeratePhysicalDevices(geInstance->vkInstance,
|
||||
&physicalDevicesCount, NULL)) return JNI_FALSE;
|
||||
|
||||
if (physicalDevicesCount == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Failed to find GPUs with Vulkan support")
|
||||
return JNI_FALSE;
|
||||
} else {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "Vulkan: Found %d physical devices:", physicalDevicesCount)
|
||||
}
|
||||
|
||||
ARRAY_RESIZE(geInstance->physicalDevices, physicalDevicesCount);
|
||||
|
||||
VK_IF_ERROR(geInstance->vkEnumeratePhysicalDevices(geInstance->vkInstance, &physicalDevicesCount,
|
||||
geInstance->physicalDevices)) return JNI_FALSE;
|
||||
|
||||
ARRAY_ENSURE_CAPACITY(geInstance->devices, physicalDevicesCount);
|
||||
|
||||
for (uint32_t i = 0; i < physicalDevicesCount; i++) {
|
||||
VkPhysicalDeviceVulkan12Features device12Features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.pNext = NULL
|
||||
};
|
||||
|
||||
VkPhysicalDeviceFeatures2 deviceFeatures2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &device12Features
|
||||
};
|
||||
|
||||
geInstance->vkGetPhysicalDeviceFeatures2(geInstance->physicalDevices[i], &deviceFeatures2);
|
||||
|
||||
VkPhysicalDeviceProperties2 deviceProperties2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
||||
geInstance->vkGetPhysicalDeviceProperties2(geInstance->physicalDevices[i], &deviceProperties2);
|
||||
J2dRlsTrace5(J2D_TRACE_INFO, "\t- %s (%d.%d.%d, %s) ",
|
||||
(const char *) deviceProperties2.properties.deviceName,
|
||||
VK_API_VERSION_MAJOR(deviceProperties2.properties.apiVersion),
|
||||
VK_API_VERSION_MINOR(deviceProperties2.properties.apiVersion),
|
||||
VK_API_VERSION_PATCH(deviceProperties2.properties.apiVersion),
|
||||
physicalDeviceTypeString(deviceProperties2.properties.deviceType))
|
||||
|
||||
if (!deviceFeatures2.features.logicOp) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, " - hasLogicOp not supported, skipped")
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!device12Features.timelineSemaphore) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, " - hasTimelineSemaphore not supported, skipped")
|
||||
continue;
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "")
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
geInstance->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
geInstance->physicalDevices[i], &queueFamilyCount, NULL);
|
||||
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
|
||||
geInstance->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
geInstance->physicalDevices[i], &queueFamilyCount, queueFamilies);
|
||||
int64_t queueFamily = -1;
|
||||
for (uint32_t j = 0; j < queueFamilyCount; j++) {
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
VkBool32 presentationSupported =
|
||||
geInstance->vkGetPhysicalDeviceWaylandPresentationSupportKHR(
|
||||
geInstance->physicalDevices[i], j, geInstance->waylandDisplay);
|
||||
#endif
|
||||
char logFlags[5] = {
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT ? 'G' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_COMPUTE_BIT ? 'C' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_TRANSFER_BIT ? 'T' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT ? 'S' : '-',
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
presentationSupported ? 'P' : '-'
|
||||
#else
|
||||
'-'
|
||||
#endif
|
||||
};
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, " %d queues in family (%.*s)", queueFamilies[j].queueCount, 5,
|
||||
logFlags)
|
||||
|
||||
// TODO use compute workloads? Separate transfer-only DMA queue?
|
||||
if (queueFamily == -1 && (queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
&& presentationSupported
|
||||
#endif
|
||||
) {
|
||||
queueFamily = j;
|
||||
}
|
||||
}
|
||||
if (queueFamily == -1) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, " --------------------- Suitable queue not found, skipped")
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t layerCount;
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i],
|
||||
&layerCount, NULL)) continue;
|
||||
VkLayerProperties layers[layerCount];
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceLayerProperties(geInstance->physicalDevices[i],
|
||||
&layerCount, layers)) continue;
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported device layers:")
|
||||
for (uint32_t j = 0; j < layerCount; j++) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) layers[j].layerName)
|
||||
}
|
||||
|
||||
uint32_t extensionCount;
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceExtensionProperties(geInstance->physicalDevices[i],
|
||||
NULL, &extensionCount, NULL)) continue;
|
||||
VkExtensionProperties extensions[extensionCount];
|
||||
VK_IF_ERROR(geInstance->vkEnumerateDeviceExtensionProperties(geInstance->physicalDevices[i],
|
||||
NULL, &extensionCount, extensions)) continue;
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, " Supported device extensions:")
|
||||
VkBool32 hasSwapChain = VK_FALSE;
|
||||
for (uint32_t j = 0; j < extensionCount; j++) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " %s", (char *) extensions[j].extensionName)
|
||||
hasSwapChain = hasSwapChain ||
|
||||
strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, extensions[j].extensionName) == 0;
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "Vulkan: Found device extensions:")
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " " VK_KHR_SWAPCHAIN_EXTENSION_NAME " = %s", hasSwapChain ? "true" : "false")
|
||||
|
||||
if (!hasSwapChain) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO,
|
||||
" --------------------- Required " VK_KHR_SWAPCHAIN_EXTENSION_NAME " not found, skipped")
|
||||
continue;
|
||||
}
|
||||
|
||||
ARRAY(pchar) deviceEnabledLayers = NULL;
|
||||
ARRAY(pchar) deviceEnabledExtensions = NULL;
|
||||
ARRAY_PUSH_BACK(deviceEnabledExtensions) = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
|
||||
|
||||
// Validation layer
|
||||
#ifdef DEBUG
|
||||
int validationLayerNotSupported = 1;
|
||||
for (uint32_t j = 0; j < layerCount; j++) {
|
||||
if (strcmp(VALIDATION_LAYER_NAME, layers[j].layerName) == 0) {
|
||||
validationLayerNotSupported = 0;
|
||||
ARRAY_PUSH_BACK(deviceEnabledLayers) = VALIDATION_LAYER_NAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (validationLayerNotSupported) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " %s device layer is not supported", VALIDATION_LAYER_NAME)
|
||||
}
|
||||
#endif
|
||||
char* deviceName = strdup(deviceProperties2.properties.deviceName);
|
||||
if (deviceName == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot duplicate deviceName")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
ARRAY_PUSH_BACK(geInstance->devices) = (VKDevice) {
|
||||
.name = deviceName,
|
||||
.handle = VK_NULL_HANDLE,
|
||||
.physicalDevice = geInstance->physicalDevices[i],
|
||||
.queueFamily = queueFamily,
|
||||
.enabledLayers = deviceEnabledLayers,
|
||||
.enabledExtensions = deviceEnabledExtensions
|
||||
};
|
||||
}
|
||||
if (ARRAY_SIZE(geInstance->devices) == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: No compatible device found")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jboolean VK_InitDevice(VKDevice* device) {
|
||||
if (device->handle != VK_NULL_HANDLE) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
if (geInstance == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: VKGraphicsEnvironment is not initialized")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (verbose) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(geInstance->devices); i++) {
|
||||
fprintf(stderr, " %c%d: %s\n", &geInstance->devices[i] == device ? '*' : ' ',
|
||||
i, geInstance->devices[i].name);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = device->queueFamily, // obtained separately
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority
|
||||
};
|
||||
|
||||
VkPhysicalDeviceFeatures features10 = { .logicOp = VK_TRUE };
|
||||
VkPhysicalDeviceVulkan12Features features12 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.timelineSemaphore = VK_TRUE
|
||||
};
|
||||
void *pNext = &features12;
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = pNext,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &queueCreateInfo,
|
||||
.enabledLayerCount = ARRAY_SIZE(device->enabledLayers),
|
||||
.ppEnabledLayerNames = (const char *const *) device->enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(device->enabledExtensions),
|
||||
.ppEnabledExtensionNames = (const char *const *) device->enabledExtensions,
|
||||
.pEnabledFeatures = &features10
|
||||
};
|
||||
|
||||
VK_IF_ERROR(geInstance->vkCreateDevice(device->physicalDevice, &createInfo, NULL, &device->handle)) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Vulkan: Cannot create device: %s", device->name)
|
||||
return JNI_FALSE;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VK_InitDevice(%s)", device->name);
|
||||
|
||||
#define DEVICE_PROC(NAME) GET_VK_PROC_RET_FALSE_IF_ERR(geInstance->vkGetDeviceProcAddr, device, device->handle, NAME)
|
||||
DEVICE_PROC(vkDestroyDevice);
|
||||
DEVICE_PROC(vkCreateShaderModule);
|
||||
DEVICE_PROC(vkDestroyShaderModule);
|
||||
DEVICE_PROC(vkCreatePipelineLayout);
|
||||
DEVICE_PROC(vkDestroyPipelineLayout);
|
||||
DEVICE_PROC(vkCreateGraphicsPipelines);
|
||||
DEVICE_PROC(vkDestroyPipeline);
|
||||
DEVICE_PROC(vkCreateSwapchainKHR);
|
||||
DEVICE_PROC(vkDestroySwapchainKHR);
|
||||
DEVICE_PROC(vkGetSwapchainImagesKHR);
|
||||
DEVICE_PROC(vkCreateImageView);
|
||||
DEVICE_PROC(vkCreateFramebuffer);
|
||||
DEVICE_PROC(vkCreateCommandPool);
|
||||
DEVICE_PROC(vkDestroyCommandPool);
|
||||
DEVICE_PROC(vkAllocateCommandBuffers);
|
||||
DEVICE_PROC(vkFreeCommandBuffers);
|
||||
DEVICE_PROC(vkCreateSemaphore);
|
||||
DEVICE_PROC(vkDestroySemaphore);
|
||||
DEVICE_PROC(vkWaitSemaphores);
|
||||
DEVICE_PROC(vkGetSemaphoreCounterValue);
|
||||
DEVICE_PROC(vkCreateFence);
|
||||
DEVICE_PROC(vkGetDeviceQueue);
|
||||
DEVICE_PROC(vkWaitForFences);
|
||||
DEVICE_PROC(vkResetFences);
|
||||
DEVICE_PROC(vkAcquireNextImageKHR);
|
||||
DEVICE_PROC(vkResetCommandBuffer);
|
||||
DEVICE_PROC(vkQueueSubmit);
|
||||
DEVICE_PROC(vkQueuePresentKHR);
|
||||
DEVICE_PROC(vkBeginCommandBuffer);
|
||||
DEVICE_PROC(vkCmdBlitImage);
|
||||
DEVICE_PROC(vkCmdPipelineBarrier);
|
||||
DEVICE_PROC(vkCmdBeginRenderPass);
|
||||
DEVICE_PROC(vkCmdExecuteCommands);
|
||||
DEVICE_PROC(vkCmdClearAttachments);
|
||||
DEVICE_PROC(vkCmdBindPipeline);
|
||||
DEVICE_PROC(vkCmdSetViewport);
|
||||
DEVICE_PROC(vkCmdSetScissor);
|
||||
DEVICE_PROC(vkCmdDraw);
|
||||
DEVICE_PROC(vkCmdEndRenderPass);
|
||||
DEVICE_PROC(vkEndCommandBuffer);
|
||||
DEVICE_PROC(vkCreateImage);
|
||||
DEVICE_PROC(vkCreateSampler);
|
||||
DEVICE_PROC(vkDestroySampler);
|
||||
DEVICE_PROC(vkAllocateMemory);
|
||||
DEVICE_PROC(vkBindImageMemory);
|
||||
DEVICE_PROC(vkCreateDescriptorSetLayout);
|
||||
DEVICE_PROC(vkDestroyDescriptorSetLayout);
|
||||
DEVICE_PROC(vkUpdateDescriptorSets);
|
||||
DEVICE_PROC(vkCreateDescriptorPool);
|
||||
DEVICE_PROC(vkDestroyDescriptorPool);
|
||||
DEVICE_PROC(vkAllocateDescriptorSets);
|
||||
DEVICE_PROC(vkCmdBindDescriptorSets);
|
||||
DEVICE_PROC(vkGetImageMemoryRequirements2);
|
||||
DEVICE_PROC(vkCreateBuffer);
|
||||
DEVICE_PROC(vkDestroyBuffer);
|
||||
DEVICE_PROC(vkCreateBufferView);
|
||||
DEVICE_PROC(vkDestroyBufferView);
|
||||
DEVICE_PROC(vkGetBufferMemoryRequirements2);
|
||||
DEVICE_PROC(vkBindBufferMemory);
|
||||
DEVICE_PROC(vkMapMemory);
|
||||
DEVICE_PROC(vkUnmapMemory);
|
||||
DEVICE_PROC(vkCmdBindVertexBuffers);
|
||||
DEVICE_PROC(vkCreateRenderPass);
|
||||
DEVICE_PROC(vkDestroyRenderPass);
|
||||
DEVICE_PROC(vkFreeMemory);
|
||||
DEVICE_PROC(vkDestroyImageView);
|
||||
DEVICE_PROC(vkDestroyImage);
|
||||
DEVICE_PROC(vkDestroyFramebuffer);
|
||||
DEVICE_PROC(vkFlushMappedMemoryRanges);
|
||||
DEVICE_PROC(vkInvalidateMappedMemoryRanges);
|
||||
DEVICE_PROC(vkCmdPushConstants);
|
||||
DEVICE_PROC(vkCmdCopyBufferToImage);
|
||||
DEVICE_PROC(vkCmdCopyImageToBuffer);
|
||||
|
||||
device->vkGetDeviceQueue(device->handle, device->queueFamily, 0, &device->queue);
|
||||
if (device->queue == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "Vulkan: Failed to get device queue");
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
device->allocator = VKAllocator_Create(device);
|
||||
if (!device->allocator) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot create allocator")
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
device->renderer = VKRenderer_Create(device);
|
||||
if (!device->renderer) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot create renderer")
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
device->texturePool = VKTexturePool_InitWithDevice(device);
|
||||
if (!device->texturePool) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot create texture pool")
|
||||
VK_UNHANDLED_ERROR();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
geInstance->currentDevice = device;
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
VKGraphicsEnvironment* VKGE_graphics_environment() {
|
||||
return geInstance;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKInstance
|
||||
* Method: init
|
||||
* Signature: (JZI)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_vulkan_VKInstance_initNative(JNIEnv *env, jclass wlge, jlong nativePtr, jboolean verb, jint requestedDevice) {
|
||||
#ifdef DEBUG
|
||||
// Init random for debug-related validation tricks.
|
||||
srand(nativePtr);
|
||||
#endif
|
||||
verbose = verb;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = vulkanLibOpen();
|
||||
if (vkGetInstanceProcAddr == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
geInstance = (VKGraphicsEnvironment*)malloc(sizeof(VKGraphicsEnvironment));
|
||||
if (geInstance == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Cannot allocate VKGraphicsEnvironment")
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
*geInstance = (VKGraphicsEnvironment) {};
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
geInstance->waylandDisplay = (struct wl_display*) jlong_to_ptr(nativePtr);
|
||||
#endif
|
||||
if (!VK_InitGraphicsEnvironment(vkGetInstanceProcAddr)) {
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (!VK_FindDevices()) {
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (requestedDevice < 0 || (uint32_t)requestedDevice >= ARRAY_SIZE(geInstance->devices)) {
|
||||
requestedDevice = 0;
|
||||
}
|
||||
if (!VK_InitDevice(&geInstance->devices[requestedDevice])) {
|
||||
vulkanLibClose();
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload(__attribute__((unused)) JavaVM *vm, __attribute__((unused)) void *reserved) {
|
||||
vulkanLibClose();
|
||||
}
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKBase_h_Included
|
||||
#define VKBase_h_Included
|
||||
#include "VKTypes.h"
|
||||
#include "VKComposites.h"
|
||||
#include "VKTexturePool.h"
|
||||
#include "VKRenderState.h"
|
||||
#include "VKUtil.h"
|
||||
|
||||
struct VKDevice {
|
||||
VkDevice handle;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
char* name;
|
||||
uint32_t queueFamily;
|
||||
ARRAY(pchar) enabledLayers;
|
||||
ARRAY(pchar) enabledExtensions;
|
||||
VkQueue queue;
|
||||
|
||||
VKAllocator* allocator;
|
||||
VKRenderer* renderer;
|
||||
VKTexturePool* texturePool;
|
||||
|
||||
PFN_vkDestroyDevice vkDestroyDevice;
|
||||
PFN_vkCreateShaderModule vkCreateShaderModule;
|
||||
PFN_vkDestroyShaderModule vkDestroyShaderModule;
|
||||
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
|
||||
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
|
||||
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
|
||||
PFN_vkDestroyPipeline vkDestroyPipeline;
|
||||
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||
PFN_vkCreateImageView vkCreateImageView;
|
||||
PFN_vkCreateFramebuffer vkCreateFramebuffer;
|
||||
PFN_vkCreateCommandPool vkCreateCommandPool;
|
||||
PFN_vkDestroyCommandPool vkDestroyCommandPool;
|
||||
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
|
||||
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
|
||||
PFN_vkCreateSemaphore vkCreateSemaphore;
|
||||
PFN_vkDestroySemaphore vkDestroySemaphore;
|
||||
PFN_vkWaitSemaphores vkWaitSemaphores;
|
||||
PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue;
|
||||
PFN_vkCreateFence vkCreateFence;
|
||||
PFN_vkGetDeviceQueue vkGetDeviceQueue;
|
||||
PFN_vkWaitForFences vkWaitForFences;
|
||||
PFN_vkResetFences vkResetFences;
|
||||
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
|
||||
PFN_vkResetCommandBuffer vkResetCommandBuffer;
|
||||
PFN_vkQueueSubmit vkQueueSubmit;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
|
||||
PFN_vkCmdBlitImage vkCmdBlitImage;
|
||||
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
|
||||
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
|
||||
PFN_vkCmdExecuteCommands vkCmdExecuteCommands;
|
||||
PFN_vkCmdClearAttachments vkCmdClearAttachments;
|
||||
PFN_vkCmdBindPipeline vkCmdBindPipeline;
|
||||
PFN_vkCmdSetViewport vkCmdSetViewport;
|
||||
PFN_vkCmdSetScissor vkCmdSetScissor;
|
||||
PFN_vkCmdDraw vkCmdDraw;
|
||||
PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
|
||||
PFN_vkEndCommandBuffer vkEndCommandBuffer;
|
||||
PFN_vkCreateImage vkCreateImage;
|
||||
PFN_vkCreateSampler vkCreateSampler;
|
||||
PFN_vkDestroySampler vkDestroySampler;
|
||||
PFN_vkAllocateMemory vkAllocateMemory;
|
||||
PFN_vkBindImageMemory vkBindImageMemory;
|
||||
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
|
||||
PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
|
||||
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
|
||||
PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
|
||||
PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
|
||||
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
|
||||
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
|
||||
PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2;
|
||||
PFN_vkCreateBuffer vkCreateBuffer;
|
||||
PFN_vkDestroyBuffer vkDestroyBuffer;
|
||||
PFN_vkCreateBufferView vkCreateBufferView;
|
||||
PFN_vkDestroyBufferView vkDestroyBufferView;
|
||||
PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2;
|
||||
PFN_vkBindBufferMemory vkBindBufferMemory;
|
||||
PFN_vkMapMemory vkMapMemory;
|
||||
PFN_vkUnmapMemory vkUnmapMemory;
|
||||
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
|
||||
PFN_vkCreateRenderPass vkCreateRenderPass;
|
||||
PFN_vkDestroyRenderPass vkDestroyRenderPass;
|
||||
PFN_vkFreeMemory vkFreeMemory;
|
||||
PFN_vkDestroyImageView vkDestroyImageView;
|
||||
PFN_vkDestroyImage vkDestroyImage;
|
||||
PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
|
||||
PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges;
|
||||
PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges;
|
||||
PFN_vkCmdPushConstants vkCmdPushConstants;
|
||||
PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
|
||||
PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
|
||||
};
|
||||
|
||||
struct VKGraphicsEnvironment {
|
||||
VkInstance vkInstance;
|
||||
ARRAY(VkPhysicalDevice) physicalDevices;
|
||||
ARRAY(VKDevice) devices;
|
||||
VKDevice* currentDevice;
|
||||
|
||||
VKComposites composites;
|
||||
|
||||
#if defined(DEBUG)
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
|
||||
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
|
||||
#endif
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
struct wl_display* waylandDisplay;
|
||||
|
||||
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR;
|
||||
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
|
||||
#endif
|
||||
|
||||
PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
|
||||
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
|
||||
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
|
||||
PFN_vkCreateInstance vkCreateInstance;
|
||||
PFN_vkDestroyInstance vkDestroyInstance;
|
||||
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
|
||||
PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2;
|
||||
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2;
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
|
||||
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
|
||||
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
|
||||
PFN_vkCreateDevice vkCreateDevice;
|
||||
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
|
||||
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
|
||||
};
|
||||
|
||||
VKGraphicsEnvironment* VKGE_graphics_environment();
|
||||
|
||||
#endif //VKBase_h_Included
|
||||
@@ -37,22 +37,79 @@
|
||||
#include "Trace.h"
|
||||
#include "VKImage.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKDevice.h"
|
||||
#include "VKTexturePool.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKRenderer.h"
|
||||
|
||||
static void VKBlitSwToTextureViaPooledTexture(VKRenderingContext* context, VKImage* dest, const SurfaceDataRasInfo *srcInfo,
|
||||
int dx1, int dy1, int dx2, int dy2) {
|
||||
#define SRCTYPE_BITS sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_BITS
|
||||
|
||||
typedef struct {
|
||||
VkFormat format;
|
||||
VKPackedSwizzle swizzle;
|
||||
} BlitSrcType;
|
||||
|
||||
// See encodeSrcType() in VKBlitLoops.java
|
||||
static BlitSrcType decodeSrcType(VKDevice* device, jshort srctype) {
|
||||
jshort type = (jshort) (srctype & sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_MASK);
|
||||
const VKSampledSrcType* entry = &device->sampledSrcTypes.table[type];
|
||||
BlitSrcType result = { entry->format, 0 };
|
||||
switch (type) {
|
||||
case sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_4BYTE: {
|
||||
uint32_t components[] = {
|
||||
((uint32_t) srctype >> SRCTYPE_BITS ) & 0b11,
|
||||
((uint32_t) srctype >> (SRCTYPE_BITS + 2)) & 0b11,
|
||||
((uint32_t) srctype >> (SRCTYPE_BITS + 4)) & 0b11,
|
||||
((uint32_t) srctype >> (SRCTYPE_BITS + 6)) & 0b11
|
||||
};
|
||||
result.swizzle = VK_PACK_SWIZZLE(
|
||||
entry->components[components[0]],
|
||||
entry->components[components[1]],
|
||||
entry->components[components[2]],
|
||||
components[3] == components[0] ? VK_COMPONENT_SWIZZLE_ONE : // Special case, a = r means no alpha.
|
||||
entry->components[components[3]]
|
||||
);
|
||||
} break;
|
||||
case sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_3BYTE: {
|
||||
uint32_t components[] = {
|
||||
((uint32_t) srctype >> SRCTYPE_BITS ) & 0b11,
|
||||
((uint32_t) srctype >> (SRCTYPE_BITS + 2)) & 0b11,
|
||||
((uint32_t) srctype >> (SRCTYPE_BITS + 4)) & 0b11
|
||||
};
|
||||
result.swizzle = VK_PACK_SWIZZLE(
|
||||
entry->components[components[0]],
|
||||
entry->components[components[1]],
|
||||
entry->components[components[2]],
|
||||
VK_COMPONENT_SWIZZLE_ONE
|
||||
);
|
||||
} break;
|
||||
default: {
|
||||
result.swizzle =
|
||||
VK_PACK_SWIZZLE(entry->components[0], entry->components[1], entry->components[2], entry->components[3]);
|
||||
} break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static AlphaType getSrcAlphaType(jshort srctype) {
|
||||
return srctype & sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_PRE_MULTIPLIED_ALPHA_BIT ?
|
||||
ALPHA_TYPE_PRE_MULTIPLIED : ALPHA_TYPE_STRAIGHT;
|
||||
}
|
||||
|
||||
static void VKTexturePoolTexture_Dispose(VKDevice* device, void* ctx) {
|
||||
VKTexturePoolHandle* hnd = (VKTexturePoolHandle*) ctx;
|
||||
VKTexturePoolHandle_ReleaseTexture(hnd);
|
||||
}
|
||||
|
||||
static void VKBlitSwToTextureViaPooledTexture(VKRenderingContext* context,
|
||||
VKSDOps *dstOps,
|
||||
const SurfaceDataRasInfo *srcInfo, jshort srctype, jint hint,
|
||||
int dx1, int dy1, int dx2, int dy2) {
|
||||
VKSDOps* surface = context->surface;
|
||||
VKDevice* device = surface->device;
|
||||
|
||||
const int sw = srcInfo->bounds.x2 - srcInfo->bounds.x1;
|
||||
const int sh = srcInfo->bounds.y2 - srcInfo->bounds.y1;
|
||||
const int dw = dx2 - dx1;
|
||||
const int dh = dy2 - dy1;
|
||||
|
||||
if (dw < sw || dh < sh) {
|
||||
J2dTraceLn4(J2D_TRACE_ERROR, "VKBlitSwToTextureViaPooledTexture: dest size: (%d, %d) less than source size: (%d, %d)", dw, dh, sw, sh);
|
||||
return;
|
||||
}
|
||||
|
||||
ARRAY(VKTxVertex) vertices = ARRAY_ALLOC(VKTxVertex, 4);
|
||||
/*
|
||||
@@ -63,9 +120,10 @@ static void VKBlitSwToTextureViaPooledTexture(VKRenderingContext* context, VKIma
|
||||
* (p4)---------(p3)
|
||||
*/
|
||||
|
||||
VKTexturePoolHandle* hnd = VKTexturePool_GetTexture(device->texturePool, sw, sh, surface->image->format);
|
||||
double u = (double)sw / VKTexturePoolHandle_GetActualWidth(hnd);
|
||||
double v = (double)sh / VKTexturePoolHandle_GetActualHeight(hnd);
|
||||
BlitSrcType type = decodeSrcType(device, srctype);
|
||||
VKTexturePoolHandle* hnd = VKTexturePool_GetTexture(device->texturePool, sw, sh, type.format);
|
||||
double u = (double)sw;
|
||||
double v = (double)sh;
|
||||
|
||||
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx1, dy1, 0.0f, 0.0f};
|
||||
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx2, dy1, u, 0.0f};
|
||||
@@ -75,126 +133,47 @@ static void VKBlitSwToTextureViaPooledTexture(VKRenderingContext* context, VKIma
|
||||
VKBuffer* renderVertexBuffer = ARRAY_TO_VERTEX_BUF(device, vertices);
|
||||
ARRAY_FREE(vertices);
|
||||
|
||||
const char *raster = srcInfo->rasBase;
|
||||
raster += (uint32_t)srcInfo->bounds.y1 * (uint32_t)srcInfo->scanStride + (uint32_t)srcInfo->bounds.x1 * (uint32_t)srcInfo->pixelStride;
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, "replaceTextureRegion src (dw, dh) : [%d, %d] dest (dx1, dy1) =[%d, %d]",
|
||||
dw, dh, dx1, dy1);
|
||||
uint32_t dataSize = sw * sh * srcInfo->pixelStride;
|
||||
char* data = malloc(dataSize);
|
||||
// copy src pixels inside src bounds to buff
|
||||
for (int row = 0; row < sh; row++) {
|
||||
memcpy(data + (row * sw * srcInfo->pixelStride), raster, sw * srcInfo->pixelStride);
|
||||
raster += (uint32_t)srcInfo->scanStride;
|
||||
}
|
||||
VKBuffer *buffer = VKBuffer_CreateFromData(device, data, dataSize);
|
||||
free(data);
|
||||
(dx2 - dx1), (dy2 - dy1), dx1, dy1);
|
||||
VKBuffer *buffer =
|
||||
VKBuffer_CreateFromRaster(device, (VKBuffer_RasterInfo){
|
||||
.data = srcInfo->rasBase,
|
||||
.x1 = srcInfo->bounds.x1,
|
||||
.y1 = srcInfo->bounds.y1,
|
||||
.w = sw,
|
||||
.h = sh,
|
||||
.pixelStride = srcInfo->pixelStride,
|
||||
.scanStride = srcInfo->scanStride
|
||||
}, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
||||
VkCommandBuffer cb = VKRenderer_Record(device->renderer);
|
||||
{
|
||||
VkImageMemoryBarrier barrier;
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
VKRenderer_AddImageBarrier(&barrier, &barrierBatch, ((VKImage *) VKTexturePoolHandle_GetTexture(hnd)),
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
if (barrierBatch.barrierCount > 0) {
|
||||
device->vkCmdPipelineBarrier(cb, barrierBatch.srcStages, barrierBatch.dstStages,
|
||||
0, 0, NULL,
|
||||
0, NULL,
|
||||
barrierBatch.barrierCount, &barrier);
|
||||
}
|
||||
VKImage_AddBarrier(&barrier, &barrierBatch, VKTexturePoolHandle_GetTexture(hnd),
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
|
||||
}
|
||||
VKImage_LoadBuffer(context->surface->device,
|
||||
VKTexturePoolHandle_GetTexture(hnd), buffer, 0, 0, sw, sh);
|
||||
{
|
||||
VkImageMemoryBarrier barrier;
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
VKRenderer_AddImageBarrier(&barrier, &barrierBatch, ((VKImage *) VKTexturePoolHandle_GetTexture(hnd)),
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
if (barrierBatch.barrierCount > 0) {
|
||||
device->vkCmdPipelineBarrier(cb, barrierBatch.srcStages, barrierBatch.dstStages,
|
||||
0, 0, NULL,
|
||||
0, NULL,
|
||||
barrierBatch.barrierCount, &barrier);
|
||||
}
|
||||
VKImage_AddBarrier(&barrier, &barrierBatch, VKTexturePoolHandle_GetTexture(hnd),
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
|
||||
}
|
||||
|
||||
VKRenderer_TextureRender(context, dest, VKTexturePoolHandle_GetTexture(hnd),
|
||||
renderVertexBuffer->handle, 4);
|
||||
VKImage* src = VKTexturePoolHandle_GetTexture(hnd);
|
||||
VkDescriptorSet srcDescriptorSet = VKImage_GetDescriptorSet(device, src, type.format, type.swizzle);
|
||||
VKRenderer_TextureRender(srcDescriptorSet, renderVertexBuffer->handle, 4, hint, SAMPLER_WRAP_BORDER);
|
||||
|
||||
// TODO: Not optimal but required for releasing raster buffer. Such Buffers should also be managed by special pools
|
||||
// TODO: Also, consider using VKRenderer_FlushRenderPass here to process pending command
|
||||
VKRenderer_Flush(device->renderer);
|
||||
VKRenderer_Sync(device->renderer);
|
||||
// TODO: Track lifecycle of the texture to avoid reuse of occupied texture
|
||||
VKTexturePoolHandle_ReleaseTexture(hnd);
|
||||
VKBuffer_Destroy(device, buffer);
|
||||
// TODO: Add proper sync for renderVertexBuffer
|
||||
// VKBuffer_Destroy(device, renderVertexBuffer);
|
||||
}
|
||||
|
||||
static void VKBlitTextureToTexture(VKRenderingContext* context, VKImage* src, VKImage* dest,
|
||||
int sx1, int sy1, int sx2, int sy2,
|
||||
double dx1, double dy1, double dx2, double dy2)
|
||||
{
|
||||
VKSDOps* surface = context->surface;
|
||||
|
||||
VKRenderer_FlushRenderPass(surface);
|
||||
|
||||
VKDevice* device = surface->device;
|
||||
|
||||
VKTxVertex* vertices = ARRAY_ALLOC(VKTxVertex, 4);
|
||||
/*
|
||||
* (p1)---------(p2)
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* (p4)---------(p3)
|
||||
*/
|
||||
|
||||
double u1 = (double)sx1 / src->extent.width;
|
||||
double v1 = (double)sy1 / src->extent.height;
|
||||
double u2 = (double)sx2 / src->extent.width;
|
||||
double v2 = (double)sy2 / src->extent.height;
|
||||
|
||||
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx1, dy1, u1, v1};
|
||||
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx2, dy1, u2, v1};
|
||||
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx1, dy2, u1, v2};
|
||||
ARRAY_PUSH_BACK(vertices) = (VKTxVertex) {dx2, dy2, u2, v2};
|
||||
|
||||
VKBuffer* renderVertexBuffer = ARRAY_TO_VERTEX_BUF(device, vertices);
|
||||
ARRAY_FREE(vertices);
|
||||
|
||||
VkCommandBuffer cb = VKRenderer_Record(device->renderer);
|
||||
{
|
||||
VkImageMemoryBarrier barrier;
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
VKRenderer_AddImageBarrier(&barrier, &barrierBatch, src,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
if (barrierBatch.barrierCount > 0) {
|
||||
device->vkCmdPipelineBarrier(cb, barrierBatch.srcStages, barrierBatch.dstStages,
|
||||
0, 0, NULL,
|
||||
0, NULL,
|
||||
barrierBatch.barrierCount, &barrier);
|
||||
}
|
||||
}
|
||||
|
||||
VKRenderer_TextureRender(context, dest, src,
|
||||
renderVertexBuffer->handle, 4);
|
||||
|
||||
// TODO: Not optimal but required for releasing raster buffer. Such Buffers should also be managed by special pools
|
||||
// TODO: Also, consider using VKRenderer_FlushRenderPass here to process pending command
|
||||
VKRenderer_Flush(device->renderer);
|
||||
VKRenderer_Sync(device->renderer);
|
||||
// TODO: Add proper sync for renderVertexBuffer
|
||||
// VKBuffer_Destroy(device, renderVertexBuffer);
|
||||
VKRenderer_FlushSurface(dstOps);
|
||||
VKRenderer_DisposeOnCleanup(device->renderer, VKTexturePoolTexture_Dispose, hnd);
|
||||
VKRenderer_DisposeOnCleanup(device->renderer, VKBuffer_Dispose, buffer);
|
||||
}
|
||||
|
||||
static jboolean clipDestCoords(
|
||||
@@ -260,94 +239,43 @@ static jboolean clipDestCoords(
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
void VKBlitLoops_IsoBlit(JNIEnv *env,
|
||||
VKRenderingContext* context, jlong pSrcOps,
|
||||
jboolean xform, jint hint,
|
||||
jboolean texture,
|
||||
jint sx1, jint sy1,
|
||||
jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1,
|
||||
jdouble dx2, jdouble dy2)
|
||||
void VKBlitLoops_IsoBlit(VKSDOps* srcOps, jint filter,
|
||||
jint sx1, jint sy1, jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
|
||||
{
|
||||
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKBlitLoops_IsoBlit: (%d %d %d %d) -> (%f %f %f %f) ",
|
||||
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKBlitLoops_IsoBlit: texture=%d xform=%d",
|
||||
texture, xform)
|
||||
|
||||
VKSDOps *srcOps = (VKSDOps *)jlong_to_ptr(pSrcOps);
|
||||
|
||||
if (context == NULL || srcOps == NULL) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_ERROR, "VKBlitLoops_IsoBlit: context(%p) or srcOps(%p) is null",
|
||||
context, srcOps)
|
||||
if (srcOps == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
||||
"VKBlitLoops_IsoBlit: srcOps is null")
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcOps->image == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_WARNING, "VKBlitLoops_IsoBlit: srcOps->image is null");
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
if (srcOps == context->surface) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKBlitLoops_IsoBlit: surface blit into itself (%p)", srcOps)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VKRenderer_Validate(context, SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)) {
|
||||
J2dTraceLn(J2D_TRACE_INFO, "VKBlitLoops_IsoBlit: VKRenderer_Validate cannot validate renderer");
|
||||
return;
|
||||
}
|
||||
// Ensure all prior drawing to src surface have finished.
|
||||
VKRenderer_FlushRenderPass(srcOps);
|
||||
|
||||
// TODO: check if srctype is supported
|
||||
VkBool32 srcOpaque = VKSD_IsOpaque(srcOps);
|
||||
AlphaType alphaType = srcOpaque ? ALPHA_TYPE_STRAIGHT : ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
static const VKPackedSwizzle OPAQUE_SWIZZLE = VK_PACK_SWIZZLE(VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_ONE);
|
||||
VKPackedSwizzle swizzle = srcOpaque ? OPAQUE_SWIZZLE : 0;
|
||||
|
||||
SurfaceDataRasInfo srcInfo;
|
||||
jint sw = sx2 - sx1;
|
||||
jint sh = sy2 - sy1;
|
||||
jdouble dw = dx2 - dx1;
|
||||
jdouble dh = dy2 - dy1;
|
||||
|
||||
if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
|
||||
J2dTraceLn(J2D_TRACE_WARNING,
|
||||
"VKBlitLoops_IsoBlit: invalid dimensions");
|
||||
return;
|
||||
}
|
||||
|
||||
srcInfo.bounds.x1 = sx1;
|
||||
srcInfo.bounds.y1 = sy1;
|
||||
srcInfo.bounds.x2 = sx2;
|
||||
srcInfo.bounds.y2 = sy2;
|
||||
|
||||
SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
|
||||
0, 0,
|
||||
srcOps->image->extent.width,
|
||||
srcOps->image->extent.height);
|
||||
|
||||
if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
|
||||
srcInfo.bounds.y2 > srcInfo.bounds.y1) {
|
||||
if (srcInfo.bounds.x1 != sx1) {
|
||||
dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
|
||||
sx1 = srcInfo.bounds.x1;
|
||||
}
|
||||
if (srcInfo.bounds.y1 != sy1) {
|
||||
dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
|
||||
sy1 = srcInfo.bounds.y1;
|
||||
}
|
||||
if (srcInfo.bounds.x2 != sx2) {
|
||||
dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
|
||||
sx2 = srcInfo.bounds.x2;
|
||||
}
|
||||
if (srcInfo.bounds.y2 != sy2) {
|
||||
dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
|
||||
sy2 = srcInfo.bounds.y2;
|
||||
}
|
||||
|
||||
if (sx2 > sx1 && sy2 > sy1) {
|
||||
VKBlitTextureToTexture(context, srcOps->image, context->surface->image,
|
||||
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
|
||||
}
|
||||
}
|
||||
VKRenderer_DrawImage(srcOps->image, alphaType, srcOps->image->format, swizzle, filter, SAMPLER_WRAP_BORDER,
|
||||
(float)sx1, (float)sy1, (float)sx2, (float)sy2, (float)dx1, (float)dy1, (float)dx2, (float)dy2);
|
||||
VKRenderer_AddSurfaceDependency(srcOps, context->surface);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VKBlitLoops_Blit(JNIEnv *env,
|
||||
VKRenderingContext* context, jlong pSrcOps,
|
||||
jboolean xform, jint hint,
|
||||
jint srctype, jboolean texture,
|
||||
jlong pSrcOps, jboolean xform, jint hint,
|
||||
jshort srctype,
|
||||
jint sx1, jint sy1,
|
||||
jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1,
|
||||
@@ -355,29 +283,24 @@ void VKBlitLoops_Blit(JNIEnv *env,
|
||||
{
|
||||
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit (%d %d %d %d) -> (%f %f %f %f) ",
|
||||
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit texture=%d xform=%d srctype=%d",
|
||||
texture, xform, srctype)
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT_Blit xform=%d srctype=%d", xform, srctype)
|
||||
|
||||
SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
|
||||
|
||||
|
||||
if (context == NULL || srcOps == NULL) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_ERROR, "VKBlitLoops_Blit: context(%p) or srcOps(%p) is null",
|
||||
context, srcOps)
|
||||
if (srcOps == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKBlitLoops_Blit: srcOps(%p) is null",
|
||||
srcOps)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!VKRenderer_Validate(context, SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)) {
|
||||
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, getSrcAlphaType(srctype))) {
|
||||
J2dTraceLn(J2D_TRACE_INFO, "VKBlitLoops_Blit: VKRenderer_Validate cannot validate renderer");
|
||||
return;
|
||||
}
|
||||
|
||||
VKRenderingContext *context = VKRenderer_GetContext();
|
||||
VKSDOps *dstOps = context->surface;
|
||||
VKImage *dest = context->surface->image;
|
||||
// if (srctype < 0 || srctype >= sizeof(RasterFormatInfos)/ sizeof(MTLRasterFormatInfo)) {
|
||||
// J2dTraceLn1(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: source pixel format %d isn't supported", srctype);
|
||||
// return;
|
||||
// }
|
||||
const jint sw = sx2 - sx1;
|
||||
const jint sh = sy2 - sy1;
|
||||
const jint dw = dx2 - dx1;
|
||||
@@ -433,14 +356,9 @@ void VKBlitLoops_Blit(JNIEnv *env,
|
||||
dstY2 += dy * (dh / sh);
|
||||
}
|
||||
|
||||
// MTLRasterFormatInfo rfi = RasterFormatInfos[srctype];
|
||||
//
|
||||
// if (texture) {
|
||||
// replaceTextureRegion(mtlc, dest, &srcInfo, &rfi, (int) dx1, (int) dy1, (int) dx2, (int) dy2);
|
||||
// } else {
|
||||
VKBlitSwToTextureViaPooledTexture(context, dest, &srcInfo,
|
||||
(int)dstX1, (int)dstY1, (int)dstX2, (int)dstY2);
|
||||
// }
|
||||
VKBlitSwToTextureViaPooledTexture(context, dstOps, &srcInfo, srctype, hint,
|
||||
(int)dstX1, (int)dstY1,
|
||||
(int)dstX2, (int)dstY2);
|
||||
}
|
||||
SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
|
||||
}
|
||||
@@ -452,10 +370,10 @@ void VKBlitLoops_Blit(JNIEnv *env,
|
||||
* memory ("Sw") surface.
|
||||
*/
|
||||
void
|
||||
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
|
||||
jlong pSrcOps, jlong pDstOps, jint dsttype,
|
||||
jint srcx, jint srcy, jint dstx, jint dsty,
|
||||
jint width, jint height)
|
||||
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env,
|
||||
jlong pSrcOps, jlong pDstOps, jint dsttype,
|
||||
jint srcx, jint srcy, jint dstx, jint dsty,
|
||||
jint width, jint height)
|
||||
{
|
||||
VKSDOps *srcOps = (VKSDOps *)jlong_to_ptr(pSrcOps);
|
||||
SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
|
||||
@@ -472,7 +390,6 @@ VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
|
||||
|
||||
RETURN_IF_NULL(srcOps);
|
||||
RETURN_IF_NULL(dstOps);
|
||||
RETURN_IF_NULL(context);
|
||||
|
||||
VKDevice* device = srcOps->device;
|
||||
VKImage* image = srcOps->image;
|
||||
@@ -519,7 +436,8 @@ VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
|
||||
dsty = dstInfo.bounds.y1;
|
||||
width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
|
||||
height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
|
||||
jsize bufferSizeInPixels = width * height;
|
||||
jsize bufferScan = width * dstInfo.pixelStride;
|
||||
jsize bufferSize = bufferScan * height;
|
||||
|
||||
pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
|
||||
pDst = PtrPixelsRow(pDst, dsty, dstInfo.scanStride);
|
||||
@@ -529,20 +447,14 @@ VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
|
||||
{
|
||||
VkImageMemoryBarrier barrier;
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
VKRenderer_AddImageBarrier(&barrier, &barrierBatch, image,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
if (barrierBatch.barrierCount > 0) {
|
||||
device->vkCmdPipelineBarrier(cb, barrierBatch.srcStages, barrierBatch.dstStages,
|
||||
0, 0, NULL,
|
||||
0, NULL,
|
||||
barrierBatch.barrierCount, &barrier);
|
||||
}
|
||||
VKImage_AddBarrier(&barrier, &barrierBatch, image,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
|
||||
}
|
||||
|
||||
VKBuffer* buffer = VKBuffer_Create(device, bufferSizeInPixels * sizeof(jint),
|
||||
VKBuffer* buffer = VKBuffer_Create(device, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
@@ -577,7 +489,17 @@ VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "VKBlitLoops_SurfaceToSwBlit: could not map buffer memory");
|
||||
} else {
|
||||
memcpy(pDst, pixelData, bufferSizeInPixels * sizeof(jint));
|
||||
if (bufferScan == dstInfo.scanStride) {
|
||||
// Tightly packed, copy in one go.
|
||||
memcpy(pDst, pixelData, bufferSize);
|
||||
} else {
|
||||
// Sparse, copy by scanlines.
|
||||
for (jint i = 0; i < height; i++) {
|
||||
memcpy(pDst, pixelData, bufferScan);
|
||||
pixelData = PtrAddBytes(pixelData, bufferScan);
|
||||
pDst = PtrAddBytes(pDst, dstInfo.scanStride);
|
||||
}
|
||||
}
|
||||
device->vkUnmapMemory(device->handle, buffer->range.memory);
|
||||
}
|
||||
VKBuffer_Destroy(device, buffer);
|
||||
|
||||
@@ -29,28 +29,26 @@
|
||||
|
||||
#include "jni.h"
|
||||
#include "sun_java2d_vulkan_VKBlitLoops.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKTypes.h"
|
||||
|
||||
void VKBlitLoops_IsoBlit(JNIEnv *env,
|
||||
VKRenderingContext* context, jlong pSrcOps,
|
||||
jboolean xform, jint hint,
|
||||
jboolean texture,
|
||||
void VKBlitLoops_IsoBlit(VKSDOps* srcOps,
|
||||
jint filter,
|
||||
jint sx1, jint sy1,
|
||||
jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1,
|
||||
jdouble dx2, jdouble dy2);
|
||||
|
||||
void VKBlitLoops_Blit(JNIEnv *env,
|
||||
VKRenderingContext* context, jlong pSrcOps,
|
||||
jlong pSrcOps,
|
||||
jboolean xform, jint hint,
|
||||
jint srctype, jboolean texture,
|
||||
jshort srctype,
|
||||
jint sx1, jint sy1,
|
||||
jint sx2, jint sy2,
|
||||
jdouble dx1, jdouble dy1,
|
||||
jdouble dx2, jdouble dy2);
|
||||
|
||||
void
|
||||
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env, VKRenderingContext* context,
|
||||
VKBlitLoops_SurfaceToSwBlit(JNIEnv *env,
|
||||
jlong pSrcOps, jlong pDstOps, jint dsttype,
|
||||
jint srcx, jint srcy, jint dstx, jint dsty,
|
||||
jint width, jint height);
|
||||
|
||||
@@ -28,8 +28,13 @@
|
||||
#include <string.h>
|
||||
#include "VKUtil.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKDevice.h"
|
||||
#include "VKRenderer.h"
|
||||
|
||||
#define VK_BUFFER_HOST_COHERENT_MEMORY
|
||||
|
||||
const size_t VK_BUFFER_CREATE_THRESHOLD = 0xDC000;
|
||||
|
||||
static VKMemory VKBuffer_DestroyBuffersOnFailure(VKDevice* device, VKMemory page, uint32_t bufferCount, VKBuffer* buffers) {
|
||||
assert(device != NULL && device->allocator != NULL);
|
||||
@@ -62,7 +67,7 @@ VKMemory VKBuffer_CreateBuffers(VKDevice* device, VkBufferUsageFlags usageFlags,
|
||||
// Check memory requirements. We aim to create maxBufferCount buffers,
|
||||
// but due to implementation-specific alignment requirements this number can be lower (unlikely though).
|
||||
VKMemoryRequirements requirements = VKAllocator_BufferRequirements(alloc, buffers[0].handle);
|
||||
VKAllocator_PadToAlignment(&requirements); // Align for array-like allocation.
|
||||
VKAllocator_PadToAlignment(alloc, &requirements); // Align for array-like allocation.
|
||||
VkDeviceSize realBufferSize = requirements.requirements.memoryRequirements.size;
|
||||
if (pageSize == 0) pageSize = (*bufferCount) * realBufferSize;
|
||||
uint32_t realBufferCount = pageSize / realBufferSize;
|
||||
@@ -220,41 +225,82 @@ VKBuffer* VKBuffer_Create(VKDevice* device, VkDeviceSize size,
|
||||
VKBuffer_Destroy(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
buffer->lastStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
buffer->lastAccess = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromData(VKDevice* device, void* vertices, VkDeviceSize bufferSize)
|
||||
void VKBuffer_Dispose(VKDevice* device, void* data) {
|
||||
VKBuffer* buffer = (VKBuffer*) data;
|
||||
VKBuffer_Destroy(device, buffer);
|
||||
}
|
||||
|
||||
VKBuffer *VKBuffer_CreateFromRaster(VKDevice *device,
|
||||
VKBuffer_RasterInfo info,
|
||||
VkPipelineStageFlags stage,
|
||||
VkAccessFlags access)
|
||||
{
|
||||
VKBuffer* buffer = VKBuffer_Create(device, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
uint32_t dataSize = info.w * info.h * info.pixelStride;
|
||||
VKBuffer *buffer = VKBuffer_Create(device, dataSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
#ifdef VK_BUFFER_HOST_COHERENT_MEMORY
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
#endif
|
||||
);
|
||||
|
||||
void* data;
|
||||
VK_IF_ERROR(device->vkMapMemory(device->handle, buffer->range.memory, 0, VK_WHOLE_SIZE, 0, &data)) {
|
||||
VKBuffer_Destroy(device, buffer);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(data, vertices, bufferSize);
|
||||
|
||||
VkMappedMemoryRange memoryRange = {
|
||||
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
|
||||
.pNext = NULL,
|
||||
.memory = buffer->range.memory,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE
|
||||
};
|
||||
char* raster = (char*)info.data + info.y1 * info.scanStride + info.x1 * info.pixelStride;;
|
||||
|
||||
|
||||
VK_IF_ERROR(device->vkFlushMappedMemoryRanges(device->handle, 1, &memoryRange)) {
|
||||
VKBuffer_Destroy(device, buffer);
|
||||
return NULL;
|
||||
// copy src pixels inside src bounds to buff
|
||||
for (size_t row = 0; row < info.h; row++) {
|
||||
memcpy((char*)data + (row * info.w * info.pixelStride), raster, info.w * info.pixelStride);
|
||||
raster += (uint32_t) info.scanStride;
|
||||
}
|
||||
device->vkUnmapMemory(device->handle, buffer->range.memory);
|
||||
|
||||
#ifndef VK_BUFFER_HOST_COHERENT_MEMORY
|
||||
device->vkFlushMappedMemoryRanges(device->handle, 1, &buffer->range);
|
||||
#endif
|
||||
|
||||
device->vkUnmapMemory(device->handle, buffer->range.memory);
|
||||
{
|
||||
VkCommandBuffer cb = VKRenderer_Record(device->renderer);
|
||||
VkBufferMemoryBarrier barrier;
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
VKRenderer_AddBufferBarrier(&barrier, &barrierBatch, buffer,
|
||||
stage, access);
|
||||
|
||||
if (barrierBatch.barrierCount > 0) {
|
||||
device->vkCmdPipelineBarrier(cb, barrierBatch.srcStages,
|
||||
barrierBatch.dstStages,
|
||||
0, 0, NULL,
|
||||
barrierBatch.barrierCount, &barrier,
|
||||
0, NULL);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromData(VKDevice* device, void* data, VkDeviceSize dataSize,
|
||||
VkPipelineStageFlags stage, VkAccessFlags access) {
|
||||
return VKBuffer_CreateFromRaster(device, (VKBuffer_RasterInfo) {
|
||||
.data = data,
|
||||
.w = dataSize,
|
||||
.h = 1,
|
||||
.scanStride = dataSize,
|
||||
.pixelStride = 1
|
||||
}, stage, access);
|
||||
}
|
||||
|
||||
void VKBuffer_Destroy(VKDevice* device, VKBuffer* buffer) {
|
||||
if (buffer != NULL) {
|
||||
if (buffer->handle != VK_NULL_HANDLE) {
|
||||
|
||||
@@ -30,10 +30,13 @@
|
||||
#include "VKTypes.h"
|
||||
|
||||
#define ARRAY_TO_VERTEX_BUF(device, vertices) \
|
||||
VKBuffer_CreateFromData(device, vertices, ARRAY_SIZE(vertices)*sizeof (vertices[0]))
|
||||
VKBuffer_CreateFromData(device, vertices, ARRAY_SIZE(vertices)*sizeof (vertices[0]),\
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)
|
||||
|
||||
struct VKBuffer {
|
||||
VkBuffer handle;
|
||||
VkPipelineStageFlagBits lastStage;
|
||||
VkAccessFlagBits lastAccess;
|
||||
// Buffer has no ownership over its memory.
|
||||
// Provided memory, offset and size must only be used to flush memory writes.
|
||||
// Allocation and freeing is done in pages.
|
||||
@@ -48,6 +51,13 @@ struct VKTexelBuffer {
|
||||
VkDescriptorSet descriptorSet;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
void* data;
|
||||
size_t x1, y1, w, h;
|
||||
size_t scanStride;
|
||||
size_t pixelStride;
|
||||
} VKBuffer_RasterInfo;
|
||||
|
||||
/**
|
||||
* Create buffers, allocate a memory page and bind them together.
|
||||
* 'pageSize' can be 0, meaning that page size is calculated based on buffer memory requirements.
|
||||
@@ -75,9 +85,15 @@ VKBuffer* VKBuffer_Create(VKDevice* device, VkDeviceSize size,
|
||||
VkBufferUsageFlags usage, VkMemoryPropertyFlags properties);
|
||||
|
||||
// TODO usage of this function is suboptimal, we need to avoid creating one-time buffers.
|
||||
VKBuffer* VKBuffer_CreateFromData(VKDevice* device, void* vertices, VkDeviceSize bufferSize);
|
||||
VKBuffer* VKBuffer_CreateFromData(VKDevice* device, void* data, VkDeviceSize dataSize,
|
||||
VkPipelineStageFlags stage, VkAccessFlags access);
|
||||
|
||||
VKBuffer* VKBuffer_CreateFromRaster(VKDevice* device, VKBuffer_RasterInfo info,
|
||||
VkPipelineStageFlags stage, VkAccessFlags access);
|
||||
|
||||
// TODO usage of this function is suboptimal, we need to avoid destroying individual buffers.
|
||||
void VKBuffer_Destroy(VKDevice* device, VKBuffer* buffer);
|
||||
|
||||
void VKBuffer_Dispose(VKDevice* device, void* ctx);
|
||||
|
||||
#endif // VKBuffer_h_Included
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKCapabilityUtil_h_Included
|
||||
#define VKCapabilityUtil_h_Included
|
||||
#include "VKUtil.h"
|
||||
|
||||
#define VK_KHR_VALIDATION_LAYER_NAME "VK_LAYER_KHRONOS_validation"
|
||||
|
||||
// Named entries are layers or extensions, arragned into on-stack linked list.
|
||||
typedef struct VKNamedEntry {
|
||||
pchar name;
|
||||
const void* found; // Pointer to the found struct.
|
||||
struct VKNamedEntry* next; // Pointer to the next entry.
|
||||
} VKNamedEntry;
|
||||
|
||||
#define DEF_NAMED_ENTRY(LIST, NAME) VKNamedEntry NAME = { NAME ## _NAME, NULL, (LIST) }; \
|
||||
if (NAME.name != NULL) (LIST) = &(NAME)
|
||||
|
||||
static void VKNamedEntry_LogAll(pchar what, pchar all, uint32_t count, size_t stride) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, " Supported %s:", what)
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (i == 0) J2dRlsTrace(J2D_TRACE_VERBOSE, " ")
|
||||
else J2dRlsTrace(J2D_TRACE_VERBOSE, ", ")
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, all)
|
||||
all += stride;
|
||||
}
|
||||
J2dRlsTrace(J2D_TRACE_VERBOSE, "\n")
|
||||
}
|
||||
|
||||
static void VKNamedEntry_LogFound(const VKNamedEntry* list) {
|
||||
for (; list != NULL; list = list->next) {
|
||||
J2dRlsTraceLn2(J2D_TRACE_INFO, " %s = %s", list->name, list->found ? "true" : "false")
|
||||
}
|
||||
}
|
||||
|
||||
static void VKNamedEntry_Match(VKNamedEntry* list, pchar all, uint32_t count, size_t stride) {
|
||||
for (; list != NULL; list = list->next) {
|
||||
pchar check = all;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (strcmp(list->name, check) == 0) {
|
||||
list->found = check;
|
||||
break;
|
||||
}
|
||||
check += stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ARRAY(pchar) VKNamedEntry_CollectNames(const VKNamedEntry* list) {
|
||||
ARRAY(pchar) result = NULL;
|
||||
for (; list != NULL; list = list->next) {
|
||||
if (list->found) ARRAY_PUSH_BACK(result) = list->name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void VKCapabilityUtil_LogErrors(int level, ARRAY(pchar) errors) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(errors); i++) {
|
||||
J2dRlsTraceLn1(level, " %s", errors[i])
|
||||
}
|
||||
}
|
||||
|
||||
#endif //VKCapabilityUtil_h_Included
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "VKComposites.h"
|
||||
|
||||
#define ALPHA_BLEND(NAME, SRC_COLOR, DST_COLOR, SRC_ALPHA, DST_ALPHA) \
|
||||
VKComposites_AddState(&map, ALPHA_COMPOSITE_ ## NAME, (VKCompositeState) \
|
||||
VKComposites_AddState(&composites, ALPHA_COMPOSITE_ ## NAME, (VKCompositeState) \
|
||||
{{ .blendEnable = VK_TRUE, \
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ ## SRC_COLOR, \
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ ## DST_COLOR, \
|
||||
@@ -34,26 +34,29 @@
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD, \
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | \
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT }, \
|
||||
{ .logicOpEnable = VK_FALSE }})
|
||||
{ .logicOpEnable = VK_FALSE }, ALPHA_TYPE_PRE_MULTIPLIED })
|
||||
|
||||
static size_t hash(const void* ptr) {
|
||||
return (size_t) *(VKCompositeMode*)ptr;
|
||||
const VKCompositeDescriptor* d = ptr;
|
||||
return (size_t) (d->mode | (d->dstOpaque << 31));
|
||||
}
|
||||
|
||||
static bool equals(const void* ap, const void* bp) {
|
||||
return *(VKCompositeMode*)ap == *(VKCompositeMode*)bp;
|
||||
const VKCompositeDescriptor *a = ap, *b = bp;
|
||||
return a->mode == b->mode && a->dstOpaque == b->dstOpaque;
|
||||
}
|
||||
|
||||
VKComposites VKComposites_Create() {
|
||||
VKComposites map = NULL;
|
||||
HASH_MAP_REHASH(map, linear_probing, &equals, &hash, ALPHA_COMPOSITE_GROUP + 2, 10, 0.75);
|
||||
const VKCompositeMode NEXT_FREE_MODE = ALPHA_COMPOSITE_GROUP + 1;
|
||||
VKComposites composites = { NULL };
|
||||
HASH_MAP_REHASH(composites.map, linear_probing, &equals, &hash, NEXT_FREE_MODE + 1, 10, 0.75);
|
||||
|
||||
VKComposites_AddState(&map, LOGIC_COMPOSITE_XOR, (VKCompositeState) {
|
||||
VKComposites_AddState(&composites, LOGIC_COMPOSITE_XOR, (VKCompositeState) {
|
||||
{ .blendEnable = VK_FALSE,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT },
|
||||
{ .logicOpEnable = VK_TRUE,
|
||||
.logicOp = VK_LOGIC_OP_XOR }});
|
||||
.logicOp = VK_LOGIC_OP_XOR }, ALPHA_TYPE_PRE_MULTIPLIED });
|
||||
|
||||
// NAME | SRC_COLOR | DST_COLOR | SRC_ALPHA | DST_ALPHA ||
|
||||
ALPHA_BLEND( CLEAR , ZERO , ZERO , ZERO , ZERO );
|
||||
@@ -69,27 +72,143 @@ VKComposites VKComposites_Create() {
|
||||
ALPHA_BLEND( DST_ATOP , ONE_MINUS_DST_ALPHA , SRC_ALPHA , ONE , ZERO );
|
||||
ALPHA_BLEND( XOR , ONE_MINUS_DST_ALPHA , ONE_MINUS_SRC_ALPHA , ONE_MINUS_DST_ALPHA , ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
VKComposites_AddState(&map, NO_COMPOSITE, (VKCompositeState) {
|
||||
VKComposites_AddState(&composites, NO_COMPOSITE, (VKCompositeState) {
|
||||
{ .blendEnable = VK_FALSE,
|
||||
.colorWriteMask = 0 }, // For stencil-only operations.
|
||||
{ .logicOpEnable = VK_FALSE }});
|
||||
{ .logicOpEnable = VK_FALSE }, ALPHA_TYPE_PRE_MULTIPLIED });
|
||||
|
||||
return map;
|
||||
return composites;
|
||||
}
|
||||
|
||||
void VKComposites_Destroy(VKComposites composites) {
|
||||
MAP_FREE(composites);
|
||||
MAP_FREE(composites.map);
|
||||
}
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
VkBlendFactor sc[2], dc[2], sa[2], da[2];
|
||||
};
|
||||
VkBlendFactor all[8];
|
||||
} VKBlendVariables;
|
||||
typedef enum {
|
||||
COLOR,
|
||||
ALPHA,
|
||||
ALL
|
||||
} VKReplace;
|
||||
static void VKComposites_ReplaceVariables(VKBlendVariables* vars, VKReplace type, VkBlendFactor of, VkBlendFactor nf) {
|
||||
for (int i = type == ALPHA ? 4 : 0; i < (type == COLOR ? 4 : 8); i++) if (vars->all[i] == of) vars->all[i] = nf;
|
||||
}
|
||||
static VkBool32 VKComposites_IsMultiplicativelyDistributive(VkBlendOp op) {
|
||||
// We can ignore MIN and MAX, as they ignore blending factors and therefore there's nothing to factor out.
|
||||
return op == VK_BLEND_OP_ADD || op == VK_BLEND_OP_SUBTRACT || op == VK_BLEND_OP_REVERSE_SUBTRACT;
|
||||
}
|
||||
static void VKComposites_CollapseCommonMultipliers(VKBlendVariables* vars, VkBlendOp colorOp, VkBlendOp alphaOp) {
|
||||
if (VKComposites_IsMultiplicativelyDistributive(colorOp) &&
|
||||
VKComposites_IsMultiplicativelyDistributive(alphaOp)) {
|
||||
for (int sc = 0; sc < 2; sc++) {
|
||||
VkBlendFactor common = VK_BLEND_FACTOR_ZERO;
|
||||
VkBlendFactor* f[4];
|
||||
if (*(f[0] = &vars->sc[sc]) == VK_BLEND_FACTOR_ONE) continue;
|
||||
common = *f[0];
|
||||
for (int dc = 0; dc < 2; dc++) {
|
||||
if (*(f[1] = &vars->dc[dc]) == VK_BLEND_FACTOR_ONE) continue;
|
||||
if (common == VK_BLEND_FACTOR_ZERO) common = *f[1];
|
||||
else if (*f[1] != VK_BLEND_FACTOR_ZERO && *f[1] != common) continue;
|
||||
for (int sa = 0; sa < 2; sa++) {
|
||||
if (*(f[2] = &vars->sa[sa]) == VK_BLEND_FACTOR_ONE) continue;
|
||||
if (common == VK_BLEND_FACTOR_ZERO) common = *f[2];
|
||||
else if (*f[2] != VK_BLEND_FACTOR_ZERO && *f[2] != common) continue;
|
||||
for (int da = 0; da < 2; da++) {
|
||||
if (*(f[3] = &vars->da[da]) == VK_BLEND_FACTOR_ONE) continue;
|
||||
if (common == VK_BLEND_FACTOR_ZERO) common = *f[3];
|
||||
else if (*f[3] != VK_BLEND_FACTOR_ZERO && *f[3] != common) continue;
|
||||
// We have found a common multiplier.
|
||||
if (common == VK_BLEND_FACTOR_ZERO) return; // All zero.
|
||||
for (int i = 0; i < 4; i++) { // Collapse.
|
||||
if (*f[i] != VK_BLEND_FACTOR_ZERO) *f[i] = VK_BLEND_FACTOR_ONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKComposites_AddState(VKComposites* composites, VKCompositeMode mode, VKCompositeState state) {
|
||||
state.blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
state.blendState.pNext = NULL;
|
||||
state.blendState.attachmentCount = 1;
|
||||
MAP_AT(*composites, mode) = state;
|
||||
state.outAlphaType = ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
MAP_AT(composites->map, (VKCompositeDescriptor) { mode, VK_FALSE }) = state;
|
||||
|
||||
// Using pre-multiplied alpha is necessary for correct blending,
|
||||
// but it can lead to information loss, which is crucial in case of opaque destinations.
|
||||
// For instance, doing SRC blend onto an opaque surface is expected to simply discard the (straight) alpha,
|
||||
// but doing this with a zero pre-multiplied alpha will always yield transparent black (0,0,0,0).
|
||||
// Here is how we are solving this:
|
||||
// General form of blending equation (r-result, s-source, sf-source factor, d-destination, df-destination factor):
|
||||
// r = OP(s * sf, d * df)
|
||||
// To restore information lost due to alpha multiplication, let's express it in straight alpha form:
|
||||
// r.a = OP(s.a * sf.a, d.a * df.a)
|
||||
// r.rgb = OP(s.rgb * s.a * sf.rgb, d.rgb * d.a * df.rgb) / r.a
|
||||
// Now, with some specific parameter combinations we might be able to get rid of 0/0-type ambiguities
|
||||
// by outputting color in a straight-alpha form.
|
||||
|
||||
// Generate opaque mode mapping, if needed.
|
||||
if (!state.blendState.logicOpEnable && state.attachmentState.blendEnable) {
|
||||
VKBlendVariables vars = {
|
||||
.sc = {VK_BLEND_FACTOR_SRC_ALPHA, state.attachmentState.srcColorBlendFactor},
|
||||
.dc = {VK_BLEND_FACTOR_DST_ALPHA, state.attachmentState.dstColorBlendFactor},
|
||||
.sa = {VK_BLEND_FACTOR_SRC_ALPHA, state.attachmentState.srcAlphaBlendFactor},
|
||||
.da = {VK_BLEND_FACTOR_DST_ALPHA, state.attachmentState.dstAlphaBlendFactor},
|
||||
};
|
||||
|
||||
// Opaque destination - replace DST_ALPHA.
|
||||
VKComposites_ReplaceVariables(&vars, ALL, VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE);
|
||||
VKComposites_ReplaceVariables(&vars, ALL, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, VK_BLEND_FACTOR_ZERO);
|
||||
VKComposites_ReplaceVariables(&vars, COLOR, VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, VK_BLEND_FACTOR_ZERO);
|
||||
VKComposites_ReplaceVariables(&vars, ALPHA, VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, VK_BLEND_FACTOR_ONE);
|
||||
|
||||
// Simplify constants.
|
||||
const float* constants = state.blendState.blendConstants;
|
||||
if (constants[0] == 0.0f && constants[1] == 0.0f && constants[2] == 0.0f) {
|
||||
VKComposites_ReplaceVariables(&vars, COLOR, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ZERO);
|
||||
VKComposites_ReplaceVariables(&vars, COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE);
|
||||
} else if (constants[0] == 1.0f && constants[1] == 1.0f && constants[2] == 1.0f) {
|
||||
VKComposites_ReplaceVariables(&vars, COLOR, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE);
|
||||
VKComposites_ReplaceVariables(&vars, COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ZERO);
|
||||
}
|
||||
if (constants[3] == 0.0f) {
|
||||
VKComposites_ReplaceVariables(&vars, ALL, VK_BLEND_FACTOR_CONSTANT_ALPHA, VK_BLEND_FACTOR_ZERO);
|
||||
VKComposites_ReplaceVariables(&vars, ALL, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, VK_BLEND_FACTOR_ONE);
|
||||
VKComposites_ReplaceVariables(&vars, ALPHA, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ZERO);
|
||||
VKComposites_ReplaceVariables(&vars, ALPHA, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE);
|
||||
} else if (constants[3] == 1.0f) {
|
||||
VKComposites_ReplaceVariables(&vars, ALL, VK_BLEND_FACTOR_CONSTANT_ALPHA, VK_BLEND_FACTOR_ONE);
|
||||
VKComposites_ReplaceVariables(&vars, ALL, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, VK_BLEND_FACTOR_ZERO);
|
||||
VKComposites_ReplaceVariables(&vars, ALPHA, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE);
|
||||
VKComposites_ReplaceVariables(&vars, ALPHA, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ZERO);
|
||||
}
|
||||
|
||||
VKComposites_CollapseCommonMultipliers(&vars,
|
||||
state.attachmentState.colorBlendOp, state.attachmentState.alphaBlendOp);
|
||||
|
||||
VkBool32 straightSrcAlpha = vars.sc[0] == VK_BLEND_FACTOR_ONE && vars.sc[1] != VK_BLEND_FACTOR_ZERO;
|
||||
if (vars.sc[1] != state.attachmentState.srcColorBlendFactor ||
|
||||
vars.dc[1] != state.attachmentState.dstColorBlendFactor || straightSrcAlpha) {
|
||||
// Need to use opaque-specific blending.
|
||||
state.attachmentState.srcColorBlendFactor = vars.sc[1];
|
||||
state.attachmentState.dstColorBlendFactor = vars.dc[1];
|
||||
state.attachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
state.attachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
state.outAlphaType = straightSrcAlpha ? ALPHA_TYPE_STRAIGHT : ALPHA_TYPE_PRE_MULTIPLIED;
|
||||
}
|
||||
}
|
||||
MAP_AT(composites->map, (VKCompositeDescriptor) { mode, VK_TRUE }) = state;
|
||||
}
|
||||
|
||||
const VKCompositeState* VKComposites_GetState(VKComposites* composites, VKCompositeMode mode) {
|
||||
VKCompositeState* state = MAP_FIND(*composites, mode);
|
||||
const VKCompositeState* VKComposites_GetState(VKComposites* composites, VKCompositeMode mode, VkBool32 dstOpaque) {
|
||||
VKCompositeState* state = MAP_FIND(composites->map, (VKCompositeDescriptor) { mode, dstOpaque });
|
||||
state->blendState.pAttachments = &state->attachmentState;
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -55,16 +55,24 @@ typedef enum {
|
||||
(COMPOSITE) <= ALPHA_COMPOSITE_GROUP ? ALPHA_COMPOSITE_GROUP : \
|
||||
NO_COMPOSITE )
|
||||
|
||||
typedef struct {
|
||||
VKCompositeMode mode;
|
||||
VkBool32 dstOpaque;
|
||||
} VKCompositeDescriptor;
|
||||
|
||||
typedef struct {
|
||||
VkPipelineColorBlendAttachmentState attachmentState;
|
||||
VkPipelineColorBlendStateCreateInfo blendState;
|
||||
AlphaType outAlphaType;
|
||||
} VKCompositeState;
|
||||
|
||||
typedef MAP(VKCompositeMode, VKCompositeState) VKComposites;
|
||||
typedef struct {
|
||||
MAP(VKCompositeDescriptor, VKCompositeState) map;
|
||||
} VKComposites;
|
||||
|
||||
VKComposites VKComposites_Create();
|
||||
void VKComposites_Destroy(VKComposites composites);
|
||||
void VKComposites_AddState(VKComposites* composites, VKCompositeMode mode, VKCompositeState state);
|
||||
const VKCompositeState* VKComposites_GetState(VKComposites* composites, VKCompositeMode mode);
|
||||
const VKCompositeState* VKComposites_GetState(VKComposites* composites, VKCompositeMode mode, VkBool32 dstOpaque);
|
||||
|
||||
#endif //VKComposites_h_Included
|
||||
|
||||
401
src/java.desktop/share/native/common/java2d/vulkan/VKDevice.c
Normal file
401
src/java.desktop/share/native/common/java2d/vulkan/VKDevice.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sun_java2d_vulkan_VKGPU.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKCapabilityUtil.h"
|
||||
#include "VKEnv.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKTexturePool.h"
|
||||
|
||||
#define CAP_PRESENTABLE_BIT sun_java2d_vulkan_VKGPU_CAP_PRESENTABLE_BIT
|
||||
|
||||
#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define VK_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
static const char* physicalDeviceTypeString(VkPhysicalDeviceType type) {
|
||||
switch (type) {
|
||||
#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r
|
||||
STR(OTHER);
|
||||
STR(INTEGRATED_GPU);
|
||||
STR(DISCRETE_GPU);
|
||||
STR(VIRTUAL_GPU);
|
||||
STR(CPU);
|
||||
#undef STR
|
||||
default: return "UNKNOWN_DEVICE_TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
static VkBool32 VKDevice_CheckAndAddFormat(VKEnv* vk, VkPhysicalDevice physicalDevice,
|
||||
ARRAY(jint)* supportedFormats, VkFormat format, const char* name) {
|
||||
VkFormatProperties formatProperties;
|
||||
vk->vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
|
||||
static const VkFormatFeatureFlags SAMPLED_FLAGS = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||
if ((formatProperties.optimalTilingFeatures & SAMPLED_FLAGS) == SAMPLED_FLAGS) {
|
||||
// Our format is supported for sampling.
|
||||
static const VkFormatFeatureFlags ATTACHMENT_FLAGS = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT |
|
||||
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
|
||||
if ((formatProperties.optimalTilingFeatures & ATTACHMENT_FLAGS) == ATTACHMENT_FLAGS) {
|
||||
// Our format is supported as a drawing destination.
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " %s (attachment)", name)
|
||||
ARRAY_PUSH_BACK(*supportedFormats) = (jint) format;
|
||||
} else J2dRlsTraceLn1(J2D_TRACE_INFO, " %s (sampled)", name)
|
||||
return VK_TRUE;
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
void VKDevice_CheckAndAdd(VKEnv* vk, VkPhysicalDevice physicalDevice) {
|
||||
// Query device properties.
|
||||
VkPhysicalDeviceVulkan12Features device12Features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.pNext = NULL
|
||||
};
|
||||
VkPhysicalDeviceFeatures2 deviceFeatures2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &device12Features
|
||||
};
|
||||
vk->vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
|
||||
VkPhysicalDeviceProperties2 deviceProperties2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
||||
vk->vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProperties2);
|
||||
|
||||
// Query supported layers.
|
||||
uint32_t layerCount;
|
||||
VK_IF_ERROR(vk->vkEnumerateDeviceLayerProperties(physicalDevice, &layerCount, NULL)) return;
|
||||
VkLayerProperties allLayers[layerCount];
|
||||
VK_IF_ERROR(vk->vkEnumerateDeviceLayerProperties(physicalDevice, &layerCount, allLayers)) return;
|
||||
|
||||
// Query supported extensions.
|
||||
uint32_t extensionCount;
|
||||
VK_IF_ERROR(vk->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &extensionCount, NULL)) return;
|
||||
VkExtensionProperties allExtensions[extensionCount];
|
||||
VK_IF_ERROR(vk->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &extensionCount, allExtensions)) return;
|
||||
|
||||
// Check API version.
|
||||
ARRAY(pchar) errors = NULL;
|
||||
jint caps = 0;
|
||||
J2dRlsTraceLn5(J2D_TRACE_INFO, "%s (%d.%d.%d, %s)",
|
||||
(const char *) deviceProperties2.properties.deviceName,
|
||||
VK_API_VERSION_MAJOR(deviceProperties2.properties.apiVersion),
|
||||
VK_API_VERSION_MINOR(deviceProperties2.properties.apiVersion),
|
||||
VK_API_VERSION_PATCH(deviceProperties2.properties.apiVersion),
|
||||
physicalDeviceTypeString(deviceProperties2.properties.deviceType))
|
||||
if (deviceProperties2.properties.apiVersion < REQUIRED_VULKAN_VERSION) {
|
||||
ARRAY_PUSH_BACK(errors) = "Unsupported API version";
|
||||
}
|
||||
|
||||
// Log layers and extensions.
|
||||
VKNamedEntry_LogAll("device layers", allLayers[0].layerName, layerCount, sizeof(VkLayerProperties));
|
||||
VKNamedEntry_LogAll("device extensions", allExtensions[0].extensionName, extensionCount, sizeof(VkExtensionProperties));
|
||||
|
||||
// Check layers.
|
||||
VKNamedEntry* layers = NULL;
|
||||
#ifdef DEBUG
|
||||
DEF_NAMED_ENTRY(layers, VK_KHR_VALIDATION_LAYER);
|
||||
#endif
|
||||
VKNamedEntry_Match(layers, allLayers[0].layerName, layerCount, sizeof(VkLayerProperties));
|
||||
|
||||
// Check extensions.
|
||||
VKNamedEntry* extensions = NULL;
|
||||
DEF_NAMED_ENTRY(extensions, VK_KHR_SWAPCHAIN_EXTENSION);
|
||||
VKNamedEntry_Match(extensions, allExtensions[0].extensionName, extensionCount, sizeof(VkExtensionProperties));
|
||||
|
||||
// Query queue family properties.
|
||||
uint32_t queueFamilyCount = 0;
|
||||
vk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
|
||||
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
|
||||
vk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
|
||||
|
||||
// Find a queue family.
|
||||
int64_t queueFamily = -1;
|
||||
for (uint32_t j = 0; j < queueFamilyCount; j++) {
|
||||
VkBool32 presentationSupported = vk->presentationSupported && VK_KHR_SWAPCHAIN_EXTENSION.found &&
|
||||
vk->platformData->checkPresentationSupport(vk, physicalDevice, j);
|
||||
char logFlags[5] = {
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT ? 'G' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_COMPUTE_BIT ? 'C' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_TRANSFER_BIT ? 'T' : '-',
|
||||
queueFamilies[j].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT ? 'S' : '-',
|
||||
presentationSupported ? 'P' : '-'
|
||||
|
||||
};
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, " %d queues in family (%.*s)", queueFamilies[j].queueCount, 5, logFlags)
|
||||
|
||||
// TODO use compute workloads? Separate transfer-only DMA queue?
|
||||
if (queueFamilies[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) { // Queue supports graphics operations.
|
||||
if (!(caps & CAP_PRESENTABLE_BIT) && presentationSupported) {
|
||||
// Queue supports presentation, choose it.
|
||||
caps |= CAP_PRESENTABLE_BIT;
|
||||
queueFamily = j;
|
||||
} else if (queueFamily == -1) {
|
||||
// We have chosen no queue so far, choose this for now.
|
||||
queueFamily = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queueFamily == -1) ARRAY_PUSH_BACK(errors) = "Suitable queue not found";
|
||||
|
||||
// Check features.
|
||||
VKNamedEntry_LogFound(layers);
|
||||
VKNamedEntry_LogFound(extensions);
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " presentable = %s", (caps & CAP_PRESENTABLE_BIT) ? "true" : "false")
|
||||
if (!(caps & CAP_PRESENTABLE_BIT)) VK_KHR_SWAPCHAIN_EXTENSION.found = NULL;
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " logicOp = %s", deviceFeatures2.features.logicOp ? "true" : "false")
|
||||
if (deviceFeatures2.features.logicOp) caps |= sun_java2d_vulkan_VKGPU_CAP_LOGIC_OP_BIT;
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " timelineSemaphore = %s", device12Features.timelineSemaphore ? "true" : "false")
|
||||
if (!device12Features.timelineSemaphore) ARRAY_PUSH_BACK(errors) = "timelineSemaphore not supported";
|
||||
|
||||
// Query supported formats.
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, " Supported device formats:")
|
||||
VKSampledSrcTypes sampledSrcTypes = {{}};
|
||||
VKSampledSrcType* SRCTYPE_4BYTE = &sampledSrcTypes.table[sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_4BYTE];
|
||||
VKSampledSrcType* SRCTYPE_3BYTE = &sampledSrcTypes.table[sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_3BYTE];
|
||||
VKSampledSrcType* SRCTYPE_565 = &sampledSrcTypes.table[sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_565];
|
||||
VKSampledSrcType* SRCTYPE_555 = &sampledSrcTypes.table[sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_555];
|
||||
ARRAY(jint) supportedFormats = NULL;
|
||||
#define CHECK_AND_ADD_FORMAT(FORMAT) VKDevice_CheckAndAddFormat(vk, physicalDevice, &supportedFormats, FORMAT, #FORMAT)
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_B8G8R8A8_UNORM) && SRCTYPE_4BYTE->format == VK_FORMAT_UNDEFINED) {
|
||||
supportedFormats[0] |= CAP_PRESENTABLE_BIT; // TODO Check presentation support.
|
||||
*SRCTYPE_4BYTE = (VKSampledSrcType) { VK_FORMAT_B8G8R8A8_UNORM, {
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A }};
|
||||
}
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_R8G8B8A8_UNORM) && SRCTYPE_4BYTE->format == VK_FORMAT_UNDEFINED) {
|
||||
*SRCTYPE_4BYTE = (VKSampledSrcType) { VK_FORMAT_R8G8B8A8_UNORM, {
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }};
|
||||
}
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_A8B8G8R8_UNORM_PACK32) && SRCTYPE_4BYTE->format == VK_FORMAT_UNDEFINED) {
|
||||
*SRCTYPE_4BYTE = (VKSampledSrcType) { VK_FORMAT_A8B8G8R8_UNORM_PACK32, {
|
||||
#ifdef VK_LITTLE_ENDIAN
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A
|
||||
#else
|
||||
VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R
|
||||
#endif
|
||||
}};
|
||||
}
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_R8G8B8_UNORM) && SRCTYPE_3BYTE->format == VK_FORMAT_UNDEFINED) {
|
||||
*SRCTYPE_3BYTE = (VKSampledSrcType) { VK_FORMAT_R8G8B8_UNORM, {
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
}
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_B8G8R8_UNORM) && SRCTYPE_3BYTE->format == VK_FORMAT_UNDEFINED) {
|
||||
*SRCTYPE_3BYTE = (VKSampledSrcType) { VK_FORMAT_B8G8R8_UNORM, {
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
}
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_R5G6B5_UNORM_PACK16) && SRCTYPE_565->format == VK_FORMAT_UNDEFINED) {
|
||||
*SRCTYPE_565 = (VKSampledSrcType) { VK_FORMAT_R5G6B5_UNORM_PACK16, {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }};
|
||||
}
|
||||
if (CHECK_AND_ADD_FORMAT(VK_FORMAT_A1R5G5B5_UNORM_PACK16) && SRCTYPE_555->format == VK_FORMAT_UNDEFINED) {
|
||||
*SRCTYPE_555 = (VKSampledSrcType) { VK_FORMAT_A1R5G5B5_UNORM_PACK16, {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
}
|
||||
#undef CHECK_AND_ADD_FORMAT
|
||||
|
||||
// Check sampled formats capabilities.
|
||||
if (SRCTYPE_4BYTE->format == VK_FORMAT_UNDEFINED) {
|
||||
ARRAY_PUSH_BACK(errors) = "4-byte sampled format not found";
|
||||
} else caps |= sun_java2d_vulkan_VKGPU_CAP_SAMPLED_4BYTE_BIT;
|
||||
if (SRCTYPE_3BYTE->format != VK_FORMAT_UNDEFINED) caps |= sun_java2d_vulkan_VKGPU_CAP_SAMPLED_3BYTE_BIT;
|
||||
if (SRCTYPE_565->format != VK_FORMAT_UNDEFINED) caps |= sun_java2d_vulkan_VKGPU_CAP_SAMPLED_565_BIT;
|
||||
if (SRCTYPE_555->format != VK_FORMAT_UNDEFINED) caps |= sun_java2d_vulkan_VKGPU_CAP_SAMPLED_555_BIT;
|
||||
|
||||
{ // Check stencil format.
|
||||
VkFormatProperties formatProperties;
|
||||
vk->vkGetPhysicalDeviceFormatProperties(physicalDevice, VK_FORMAT_S8_UINT, &formatProperties);
|
||||
if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, " %s", "VK_FORMAT_S8_UINT (stencil)")
|
||||
} else ARRAY_PUSH_BACK(errors) = "VK_FORMAT_S8_UINT not supported";
|
||||
}
|
||||
|
||||
// Check found errors.
|
||||
if (errors != NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_WARNING, " Device is not supported:")
|
||||
VKCapabilityUtil_LogErrors(J2D_TRACE_WARNING, errors);
|
||||
ARRAY_FREE(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy device name.
|
||||
char* deviceName = strdup(deviceProperties2.properties.deviceName);
|
||||
if (deviceName == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, " Cannot duplicate deviceName")
|
||||
ARRAY_FREE(supportedFormats);
|
||||
return;
|
||||
}
|
||||
|
||||
// Valid device, add.
|
||||
ARRAY_PUSH_BACK(vk->devices) = (VKDevice) {
|
||||
.name = deviceName,
|
||||
.type = deviceProperties2.properties.deviceType,
|
||||
.nonCoherentAtomSize = deviceProperties2.properties.limits.nonCoherentAtomSize,
|
||||
.handle = VK_NULL_HANDLE,
|
||||
.physicalDevice = physicalDevice,
|
||||
.queueFamily = queueFamily,
|
||||
.enabledLayers = VKNamedEntry_CollectNames(layers),
|
||||
.enabledExtensions = VKNamedEntry_CollectNames(extensions),
|
||||
.sampledSrcTypes = sampledSrcTypes,
|
||||
.supportedFormats = supportedFormats,
|
||||
.caps = caps
|
||||
};
|
||||
}
|
||||
|
||||
void VKDevice_Reset(VKDevice* device) {
|
||||
if (device == NULL) return;
|
||||
VKRenderer_Destroy(device->renderer);
|
||||
VKTexturePool_Dispose(device->texturePool);
|
||||
VKAllocator_Destroy(device->allocator);
|
||||
ARRAY_FREE(device->enabledExtensions);
|
||||
ARRAY_FREE(device->enabledLayers);
|
||||
ARRAY_FREE(device->supportedFormats);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKDevice_Reset(%s)", device->name);
|
||||
free(device->name);
|
||||
if (device->vkDestroyDevice != NULL) {
|
||||
device->vkDestroyDevice(device->handle, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKGPU
|
||||
* Method: reset
|
||||
* Signature: (J)void
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_VKGPU_reset(JNIEnv *env, jclass jClass, jlong jDevice) {
|
||||
VKDevice* device = jlong_to_ptr(jDevice);
|
||||
if (device == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "jDevice is NULL");
|
||||
return;
|
||||
}
|
||||
VKDevice_Reset(device);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKGPU
|
||||
* Method: init
|
||||
* Signature: (J)void
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_java2d_vulkan_VKGPU_init(JNIEnv *env, jclass jClass, jlong jDevice) {
|
||||
VKDevice* device = jlong_to_ptr(jDevice);
|
||||
if (device == NULL) {
|
||||
JNU_ThrowByName(env, "java/lang/IllegalStateException", "jDevice is NULL");
|
||||
return;
|
||||
}
|
||||
if (device->handle != VK_NULL_HANDLE) return;
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = device->queueFamily, // obtained separately
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority
|
||||
};
|
||||
|
||||
VkPhysicalDeviceFeatures features10 = { .logicOp = device->caps & sun_java2d_vulkan_VKGPU_CAP_LOGIC_OP_BIT ? VK_TRUE : VK_FALSE };
|
||||
VkPhysicalDeviceVulkan12Features features12 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.timelineSemaphore = VK_TRUE
|
||||
};
|
||||
void *pNext = &features12;
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = pNext,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = 1,
|
||||
.pQueueCreateInfos = &queueCreateInfo,
|
||||
.enabledLayerCount = ARRAY_SIZE(device->enabledLayers),
|
||||
.ppEnabledLayerNames = (const char *const *) device->enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(device->enabledExtensions),
|
||||
.ppEnabledExtensionNames = (const char *const *) device->enabledExtensions,
|
||||
.pEnabledFeatures = &features10
|
||||
};
|
||||
|
||||
VKEnv* vk = VKEnv_GetInstance();
|
||||
VK_IF_ERROR(vk->vkCreateDevice(device->physicalDevice, &createInfo, NULL, &device->handle)) {
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Cannot create device");
|
||||
return;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKDevice_init(%s)", device->name);
|
||||
|
||||
VkBool32 missingAPI = JNI_FALSE;
|
||||
DEVICE_FUNCTION_TABLE(CHECK_PROC_ADDR, missingAPI, vk->vkGetDeviceProcAddr, device->handle, device->)
|
||||
if (device->caps & CAP_PRESENTABLE_BIT) {
|
||||
SWAPCHAIN_DEVICE_FUNCTION_TABLE(CHECK_PROC_ADDR, missingAPI, vk->vkGetDeviceProcAddr, device->handle, device->)
|
||||
}
|
||||
if (missingAPI) {
|
||||
VKDevice_Reset(device);
|
||||
#define REQUIRED_API_MISSING_MESSAGE "Vulkan: Required API is missing: "
|
||||
size_t size = sizeof(REQUIRED_API_MISSING_MESSAGE);
|
||||
#define PFN_CALC_MISSING_NAMES_SIZE(_, NAME) if (device->NAME == NULL) size += sizeof(#NAME) + 1;
|
||||
DEVICE_FUNCTION_TABLE(PFN_CALC_MISSING_NAMES_SIZE)
|
||||
if (device->caps & CAP_PRESENTABLE_BIT) { SWAPCHAIN_DEVICE_FUNCTION_TABLE(PFN_CALC_MISSING_NAMES_SIZE) }
|
||||
char message[size];
|
||||
memcpy(message, REQUIRED_API_MISSING_MESSAGE, size = sizeof(REQUIRED_API_MISSING_MESSAGE) - 1);
|
||||
#define PFN_APPEND_MISSING_NAME(_, NAME) if (device->NAME == NULL) { \
|
||||
memcpy(message + size, #NAME ", ", sizeof(#NAME) + 1); size += sizeof(#NAME) + 1; }
|
||||
DEVICE_FUNCTION_TABLE(PFN_APPEND_MISSING_NAME)
|
||||
if (device->caps & CAP_PRESENTABLE_BIT) { SWAPCHAIN_DEVICE_FUNCTION_TABLE(PFN_APPEND_MISSING_NAME) }
|
||||
message[size - 2] = '\0';
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", message);
|
||||
return;
|
||||
}
|
||||
|
||||
device->vkGetDeviceQueue(device->handle, device->queueFamily, 0, &device->queue);
|
||||
if (device->queue == NULL) {
|
||||
VKDevice_Reset(device);
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Vulkan: Failed to get device queue");
|
||||
return;
|
||||
}
|
||||
|
||||
device->allocator = VKAllocator_Create(device);
|
||||
if (!device->allocator) {
|
||||
VKDevice_Reset(device);
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Vulkan: Cannot create allocator");
|
||||
return;
|
||||
}
|
||||
|
||||
device->renderer = VKRenderer_Create(device);
|
||||
if (!device->renderer) {
|
||||
VKDevice_Reset(device);
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Vulkan: Cannot create renderer");
|
||||
return;
|
||||
}
|
||||
|
||||
device->texturePool = VKTexturePool_InitWithDevice(device);
|
||||
if (!device->texturePool) {
|
||||
VKDevice_Reset(device);
|
||||
JNU_ThrowByName(env, "java/lang/RuntimeException", "Vulkan: Cannot create texture pool");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKDevice_h_Included
|
||||
#define VKDevice_h_Included
|
||||
#include "sun_java2d_vulkan_VKSwToSurfaceBlit.h"
|
||||
#include "VKTexturePool.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKFunctionTable.h"
|
||||
|
||||
/**
|
||||
* Description of a sampled source type bound to a specific format, supported on the device.
|
||||
*/
|
||||
typedef struct {
|
||||
VkFormat format;
|
||||
VkComponentSwizzle components[4];
|
||||
} VKSampledSrcType;
|
||||
|
||||
typedef struct {
|
||||
VKSampledSrcType table[1 << sun_java2d_vulkan_VKSwToSurfaceBlit_SRCTYPE_BITS];
|
||||
} VKSampledSrcTypes;
|
||||
|
||||
struct VKDevice {
|
||||
VkDevice handle;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
char* name;
|
||||
VkPhysicalDeviceType type;
|
||||
VkDeviceSize nonCoherentAtomSize;
|
||||
uint32_t queueFamily;
|
||||
ARRAY(pchar) enabledLayers;
|
||||
ARRAY(pchar) enabledExtensions;
|
||||
VkQueue queue;
|
||||
VKSampledSrcTypes sampledSrcTypes;
|
||||
ARRAY(jint) supportedFormats;
|
||||
jint caps;
|
||||
|
||||
VKAllocator* allocator;
|
||||
VKRenderer* renderer;
|
||||
VKTexturePool* texturePool;
|
||||
|
||||
DEVICE_FUNCTION_TABLE(DECL_PFN)
|
||||
SWAPCHAIN_DEVICE_FUNCTION_TABLE(DECL_PFN)
|
||||
};
|
||||
|
||||
#endif //VKDevice_h_Included
|
||||
386
src/java.desktop/share/native/common/java2d/vulkan/VKEnv.c
Normal file
386
src/java.desktop/share/native/common/java2d/vulkan/VKEnv.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2024, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include "VKUtil.h"
|
||||
#include "VKCapabilityUtil.h"
|
||||
#include "VKEnv.h"
|
||||
#include "VKDevice.h"
|
||||
|
||||
#define VULKAN_DLL JNI_LIB_NAME("vulkan")
|
||||
#define VULKAN_1_DLL VERSIONED_JNI_LIB_NAME("vulkan", "1")
|
||||
|
||||
static void* pVulkanLib = NULL;
|
||||
static void vulkanLibClose() {
|
||||
if (pVulkanLib != NULL) {
|
||||
dlclose(pVulkanLib);
|
||||
pVulkanLib = NULL;
|
||||
}
|
||||
}
|
||||
static PFN_vkGetInstanceProcAddr vulkanLibOpen() {
|
||||
if (pVulkanLib == NULL) {
|
||||
pVulkanLib = dlopen(VULKAN_DLL, RTLD_NOW);
|
||||
if (pVulkanLib == NULL) {
|
||||
pVulkanLib = dlopen(VULKAN_1_DLL, RTLD_NOW);
|
||||
}
|
||||
if (pVulkanLib == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "Vulkan: Failed to load %s", VULKAN_DLL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dlsym(pVulkanLib, "vkGetInstanceProcAddr");
|
||||
if (vkGetInstanceProcAddr == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR,
|
||||
"Vulkan: Failed to get proc address of vkGetInstanceProcAddr from %s", VULKAN_DLL)
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
return vkGetInstanceProcAddr;
|
||||
}
|
||||
|
||||
void VKDevice_Reset(VKDevice* device);
|
||||
|
||||
static void VKEnv_Destroy(VKEnv* vk) {
|
||||
if (vk == NULL) return;
|
||||
|
||||
if (vk->devices != NULL) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(vk->devices); i++) {
|
||||
VKDevice_Reset(&vk->devices[i]);
|
||||
}
|
||||
ARRAY_FREE(vk->devices);
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
if (vk->vkDestroyDebugUtilsMessengerEXT != NULL && vk->instance != VK_NULL_HANDLE) {
|
||||
vk->vkDestroyDebugUtilsMessengerEXT(vk->instance, vk->debugMessenger, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
VKComposites_Destroy(vk->composites);
|
||||
|
||||
if (vk->vkDestroyInstance != NULL) {
|
||||
vk->vkDestroyInstance(vk->instance, NULL);
|
||||
}
|
||||
free(vk);
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "VKEnv_Destroy");
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
static VkBool32 debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData
|
||||
) {
|
||||
if (pCallbackData == NULL) return VK_FALSE;
|
||||
// Here we can filter messages like this:
|
||||
// if (std::strcmp(pCallbackData->pMessageIdName, "UNASSIGNED-BestPractices-DrawState-ClearCmdBeforeDraw") == 0) return VK_FALSE;
|
||||
|
||||
int level = J2D_TRACE_OFF;
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) level = J2D_TRACE_VERBOSE;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) level = J2D_TRACE_INFO;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) level = J2D_TRACE_WARNING;
|
||||
else if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) level = J2D_TRACE_ERROR;
|
||||
|
||||
J2dRlsTraceLn(level, pCallbackData->pMessage);
|
||||
|
||||
if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
VK_FATAL_ERROR("Unhandled Vulkan validation error");
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static VKEnv* VKEnv_Create(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, VKPlatformData* platformData) {
|
||||
if (vkGetInstanceProcAddr == NULL) return NULL;
|
||||
|
||||
// Init global function table.
|
||||
VkBool32 missingAPI = JNI_FALSE;
|
||||
GLOBAL_FUNCTION_TABLE(DECL_PFN)
|
||||
GLOBAL_FUNCTION_TABLE(CHECK_PROC_ADDR, missingAPI, vkGetInstanceProcAddr, NULL,)
|
||||
if (missingAPI) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Required API is missing:")
|
||||
GLOBAL_FUNCTION_TABLE(LOG_MISSING_PFN,)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Query API version.
|
||||
uint32_t apiVersion = 0;
|
||||
VK_IF_ERROR(vkEnumerateInstanceVersion(&apiVersion)) return NULL;
|
||||
J2dRlsTraceLn3(J2D_TRACE_INFO, "Vulkan: Available (%d.%d.%d)",
|
||||
VK_API_VERSION_MAJOR(apiVersion),
|
||||
VK_API_VERSION_MINOR(apiVersion),
|
||||
VK_API_VERSION_PATCH(apiVersion))
|
||||
|
||||
// Query supported layers.
|
||||
uint32_t layerCount;
|
||||
VK_IF_ERROR(vkEnumerateInstanceLayerProperties(&layerCount, NULL)) return NULL;
|
||||
VkLayerProperties allLayers[layerCount];
|
||||
VK_IF_ERROR(vkEnumerateInstanceLayerProperties(&layerCount, allLayers)) return NULL;
|
||||
|
||||
// Query supported extensions.
|
||||
uint32_t extensionCount;
|
||||
VK_IF_ERROR(vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL)) return NULL;
|
||||
VkExtensionProperties allExtensions[extensionCount];
|
||||
VK_IF_ERROR(vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, allExtensions)) return NULL;
|
||||
|
||||
// Log layers and extensions.
|
||||
VKNamedEntry_LogAll("instance layers", allLayers[0].layerName, layerCount, sizeof(VkLayerProperties));
|
||||
VKNamedEntry_LogAll("instance extensions", allExtensions[0].extensionName, extensionCount, sizeof(VkExtensionProperties));
|
||||
|
||||
// Check API version.
|
||||
ARRAY(pchar) errors = NULL;
|
||||
if (apiVersion < REQUIRED_VULKAN_VERSION) ARRAY_PUSH_BACK(errors) = "Unsupported API version";
|
||||
|
||||
// Check layers.
|
||||
VKNamedEntry* layers = NULL;
|
||||
#ifdef DEBUG
|
||||
DEF_NAMED_ENTRY(layers, VK_KHR_VALIDATION_LAYER);
|
||||
#endif
|
||||
VKNamedEntry_Match(layers, allLayers[0].layerName, layerCount, sizeof(VkLayerProperties));
|
||||
VKNamedEntry_LogFound(layers);
|
||||
|
||||
// Check extensions.
|
||||
pchar PLATFORM_SURFACE_EXTENSION_NAME = platformData != NULL ? platformData->surfaceExtensionName : NULL;
|
||||
VKNamedEntry* extensions = NULL;
|
||||
DEF_NAMED_ENTRY(extensions, PLATFORM_SURFACE_EXTENSION);
|
||||
DEF_NAMED_ENTRY(extensions, VK_KHR_SURFACE_EXTENSION);
|
||||
#ifdef DEBUG
|
||||
DEF_NAMED_ENTRY(extensions, VK_EXT_DEBUG_UTILS_EXTENSION);
|
||||
#endif
|
||||
VKNamedEntry_Match(extensions, allExtensions[0].extensionName, extensionCount, sizeof(VkExtensionProperties));
|
||||
VKNamedEntry_LogFound(extensions);
|
||||
|
||||
// Check found errors.
|
||||
if (errors != NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, " Vulkan is not supported:")
|
||||
VKCapabilityUtil_LogErrors(J2D_TRACE_ERROR, errors);
|
||||
ARRAY_FREE(errors);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check presentation support.
|
||||
VkBool32 presentationSupported = PLATFORM_SURFACE_EXTENSION.found && VK_KHR_SURFACE_EXTENSION.found;
|
||||
if (!presentationSupported) PLATFORM_SURFACE_EXTENSION.found = VK_KHR_SURFACE_EXTENSION.found = NULL;
|
||||
|
||||
// Configure validation
|
||||
void *pNext = NULL;
|
||||
#ifdef DEBUG
|
||||
VkValidationFeatureEnableEXT enables[] = {
|
||||
// VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
|
||||
// VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
||||
// VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT
|
||||
};
|
||||
VkValidationFeaturesEXT features = {
|
||||
.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
|
||||
.enabledValidationFeatureCount = SARRAY_COUNT_OF(enables),
|
||||
.pEnabledValidationFeatures = enables
|
||||
};
|
||||
if (VK_KHR_VALIDATION_LAYER.found && VK_EXT_DEBUG_UTILS_EXTENSION.found) {
|
||||
pNext = &features;
|
||||
} else {
|
||||
VK_KHR_VALIDATION_LAYER.found = VK_EXT_DEBUG_UTILS_EXTENSION.found = NULL;
|
||||
J2dRlsTraceLn(J2D_TRACE_WARNING, " Vulkan validation is not supported")
|
||||
}
|
||||
#endif
|
||||
|
||||
VKEnv* vk = malloc(sizeof(VKEnv));
|
||||
if (vk == NULL) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, " Cannot allocate VKEnv")
|
||||
return NULL;
|
||||
}
|
||||
*vk = (VKEnv) {
|
||||
.platformData = platformData,
|
||||
.presentationSupported = presentationSupported
|
||||
};
|
||||
|
||||
ARRAY(pchar) enabledLayers = VKNamedEntry_CollectNames(layers);
|
||||
ARRAY(pchar) enabledExtensions = VKNamedEntry_CollectNames(extensions);
|
||||
|
||||
VkApplicationInfo applicationInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pNext = NULL,
|
||||
.pApplicationName = "OpenJDK",
|
||||
.applicationVersion = 0,
|
||||
.pEngineName = "OpenJDK",
|
||||
.engineVersion = 0,
|
||||
.apiVersion = REQUIRED_VULKAN_VERSION
|
||||
};
|
||||
|
||||
VkInstanceCreateInfo instanceCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pNext = pNext,
|
||||
.flags = 0,
|
||||
.pApplicationInfo = &applicationInfo,
|
||||
.enabledLayerCount = ARRAY_SIZE(enabledLayers),
|
||||
.ppEnabledLayerNames = enabledLayers,
|
||||
.enabledExtensionCount = ARRAY_SIZE(enabledExtensions),
|
||||
.ppEnabledExtensionNames = enabledExtensions
|
||||
};
|
||||
|
||||
VK_IF_ERROR(vkCreateInstance(&instanceCreateInfo, NULL, &vk->instance)) {
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
VKEnv_Destroy(vk);
|
||||
return NULL;
|
||||
}
|
||||
J2dRlsTraceLn(J2D_TRACE_INFO, "Vulkan: Instance Created")
|
||||
ARRAY_FREE(enabledLayers);
|
||||
ARRAY_FREE(enabledExtensions);
|
||||
|
||||
INSTANCE_FUNCTION_TABLE(CHECK_PROC_ADDR, missingAPI, vkGetInstanceProcAddr, vk->instance, vk->)
|
||||
DEBUG_INSTANCE_FUNCTION_TABLE(GET_PROC_ADDR, vkGetInstanceProcAddr, vk->instance, vk->)
|
||||
if (missingAPI) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Required API is missing:")
|
||||
INSTANCE_FUNCTION_TABLE(LOG_MISSING_PFN, vk->)
|
||||
VKEnv_Destroy(vk);
|
||||
return NULL;
|
||||
}
|
||||
if (presentationSupported) {
|
||||
SURFACE_INSTANCE_FUNCTION_TABLE(CHECK_PROC_ADDR, missingAPI, vkGetInstanceProcAddr, vk->instance, vk->)
|
||||
if (missingAPI) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: Required API is missing:")
|
||||
SURFACE_INSTANCE_FUNCTION_TABLE(LOG_MISSING_PFN, vk->)
|
||||
}
|
||||
if (missingAPI || !vk->platformData->initFunctions(vk, vkGetInstanceProcAddr)) {
|
||||
vk->presentationSupported = presentationSupported = VK_FALSE;
|
||||
}
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "Vulkan: Presentation supported = %s", presentationSupported ? "true" : "false")
|
||||
|
||||
vk->composites = VKComposites_Create();
|
||||
|
||||
// Create debug messenger
|
||||
#if defined(DEBUG)
|
||||
if (VK_KHR_VALIDATION_LAYER.found && VK_EXT_DEBUG_UTILS_EXTENSION.found &&
|
||||
vk->vkCreateDebugUtilsMessengerEXT != NULL && pNext) {
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||
.flags = 0,
|
||||
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||
.pfnUserCallback = &debugCallback
|
||||
};
|
||||
VK_IF_ERROR(vk->vkCreateDebugUtilsMessengerEXT(vk->instance, &debugUtilsMessengerCreateInfo,
|
||||
NULL, &vk->debugMessenger)) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
return vk;
|
||||
}
|
||||
|
||||
void VKDevice_CheckAndAdd(VKEnv* vk, VkPhysicalDevice physicalDevice);
|
||||
|
||||
static VkBool32 VKEnv_FindDevices(VKEnv* vk) {
|
||||
uint32_t count;
|
||||
VK_IF_ERROR(vk->vkEnumeratePhysicalDevices(vk->instance, &count, NULL)) return JNI_FALSE;
|
||||
VkPhysicalDevice physicalDevices[count];
|
||||
VK_IF_ERROR(vk->vkEnumeratePhysicalDevices(vk->instance, &count, physicalDevices)) return JNI_FALSE;
|
||||
ARRAY_ENSURE_CAPACITY(vk->devices, count);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "Vulkan: Found %d physical devices:", count)
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
VKDevice_CheckAndAdd(vk, physicalDevices[i]);
|
||||
}
|
||||
if (ARRAY_SIZE(vk->devices) == 0) {
|
||||
J2dRlsTraceLn(J2D_TRACE_ERROR, "Vulkan: No compatible device found")
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
static jobjectArray createJavaGPUs(JNIEnv *env, VKEnv* vk) {
|
||||
jclass deviceClass = (*env)->FindClass(env, "sun/java2d/vulkan/VKGPU");
|
||||
if (deviceClass == NULL) return NULL;
|
||||
jmethodID deviceConstructor = (*env)->GetMethodID(env, deviceClass, "<init>", "(JLjava/lang/String;II[I)V");
|
||||
if (deviceConstructor == NULL) return NULL;
|
||||
jobjectArray deviceArray = (*env)->NewObjectArray(env, ARRAY_SIZE(vk->devices), deviceClass, NULL);
|
||||
if (deviceArray == NULL) return NULL;
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(vk->devices); i++) {
|
||||
jstring name = JNU_NewStringPlatform(env, vk->devices[i].name);
|
||||
if (name == NULL) return NULL;
|
||||
jintArray supportedFormats = (*env)->NewIntArray(env, ARRAY_SIZE(vk->devices[i].supportedFormats));
|
||||
if (supportedFormats == NULL) return NULL;
|
||||
(*env)->SetIntArrayRegion(env, supportedFormats, 0, ARRAY_SIZE(vk->devices[i].supportedFormats), vk->devices[i].supportedFormats);
|
||||
jobject device = (*env)->NewObject(env, deviceClass, deviceConstructor,
|
||||
ptr_to_jlong(&vk->devices[i]), name, vk->devices[i].type,
|
||||
vk->devices[i].caps, supportedFormats);
|
||||
if (device == NULL) return NULL;
|
||||
(*env)->SetObjectArrayElement(env, deviceArray, i, device);
|
||||
}
|
||||
return deviceArray;
|
||||
}
|
||||
|
||||
static VKEnv* instance = NULL;
|
||||
JNIEXPORT VKEnv* VKEnv_GetInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKEnv
|
||||
* Method: initNative
|
||||
* Signature: (J)[Lsun/java2d/vulkan/VKDevice;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_sun_java2d_vulkan_VKEnv_initNative(JNIEnv* env, jclass vkenv, jlong platformData) {
|
||||
#ifdef DEBUG
|
||||
// Init random for debug-related validation tricks.
|
||||
srand(platformData);
|
||||
#endif
|
||||
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = vulkanLibOpen();
|
||||
if (vkGetInstanceProcAddr == NULL) return NULL;
|
||||
|
||||
VKEnv* vk = VKEnv_Create(vkGetInstanceProcAddr, jlong_to_ptr(platformData));
|
||||
if (vk == NULL) {
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!VKEnv_FindDevices(vk)) {
|
||||
VKEnv_Destroy(vk);
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobjectArray deviceArray = createJavaGPUs(env, vk);
|
||||
if (deviceArray == NULL) {
|
||||
VKEnv_Destroy(vk);
|
||||
vulkanLibClose();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
instance = vk;
|
||||
return deviceArray;
|
||||
}
|
||||
71
src/java.desktop/share/native/common/java2d/vulkan/VKEnv.h
Normal file
71
src/java.desktop/share/native/common/java2d/vulkan/VKEnv.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKEnv_h_Included
|
||||
#define VKEnv_h_Included
|
||||
#include "VKComposites.h"
|
||||
#include "VKDevice.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKFunctionTable.h"
|
||||
|
||||
// For old Vulkan headers - define version-related macros.
|
||||
#ifndef VK_MAKE_API_VERSION
|
||||
# define VK_MAKE_API_VERSION(variant, major, minor, patch) VK_MAKE_VERSION(major, minor, patch)
|
||||
# define VK_API_VERSION_MAJOR(version) VK_VERSION_MAJOR(version)
|
||||
# define VK_API_VERSION_MINOR(version) VK_VERSION_MINOR(version)
|
||||
# define VK_API_VERSION_PATCH(version) VK_VERSION_PATCH(version)
|
||||
#endif
|
||||
static const uint32_t REQUIRED_VULKAN_VERSION = VK_MAKE_API_VERSION(0, 1, 2, 0);
|
||||
|
||||
typedef VkBool32 (*VKPlatform_InitFunctions)(VKEnv* vk, PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr);
|
||||
typedef VkBool32 (*VKPlatform_CheckPresentationSupport)(VKEnv* vk, VkPhysicalDevice device, uint32_t queueFamily);
|
||||
typedef struct {
|
||||
const char* surfaceExtensionName;
|
||||
VKPlatform_InitFunctions initFunctions;
|
||||
VKPlatform_CheckPresentationSupport checkPresentationSupport;
|
||||
} VKPlatformData;
|
||||
|
||||
struct VKEnv {
|
||||
VkInstance instance;
|
||||
ARRAY(VKDevice) devices;
|
||||
|
||||
VKComposites composites;
|
||||
|
||||
#if defined(DEBUG)
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
#endif
|
||||
|
||||
VKPlatformData* platformData;
|
||||
VkBool32 presentationSupported;
|
||||
|
||||
INSTANCE_FUNCTION_TABLE(DECL_PFN)
|
||||
SURFACE_INSTANCE_FUNCTION_TABLE(DECL_PFN)
|
||||
DEBUG_INSTANCE_FUNCTION_TABLE(DECL_PFN)
|
||||
};
|
||||
|
||||
VKEnv* VKEnv_GetInstance();
|
||||
|
||||
#endif //VKEnv_h_Included
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef VKFunctionTable_h_Included
|
||||
#define VKFunctionTable_h_Included
|
||||
|
||||
// Enumeration of all used Vulkan functions via includer-provided FUNCTION_TABLE_ENTRY macro.
|
||||
|
||||
// Global functions.
|
||||
#define GLOBAL_FUNCTION_TABLE(ENTRY, ...) \
|
||||
ENTRY(__VA_ARGS__, vkEnumerateInstanceVersion); \
|
||||
ENTRY(__VA_ARGS__, vkEnumerateInstanceExtensionProperties); \
|
||||
ENTRY(__VA_ARGS__, vkEnumerateInstanceLayerProperties); \
|
||||
ENTRY(__VA_ARGS__, vkCreateInstance); \
|
||||
|
||||
// Instance functions.
|
||||
#define INSTANCE_FUNCTION_TABLE(ENTRY, ...) \
|
||||
ENTRY(__VA_ARGS__, vkDestroyInstance); \
|
||||
ENTRY(__VA_ARGS__, vkEnumeratePhysicalDevices); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceMemoryProperties); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceFeatures2); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceProperties2); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceQueueFamilyProperties); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceFormatProperties); \
|
||||
ENTRY(__VA_ARGS__, vkEnumerateDeviceLayerProperties); \
|
||||
ENTRY(__VA_ARGS__, vkEnumerateDeviceExtensionProperties); \
|
||||
ENTRY(__VA_ARGS__, vkCreateDevice); \
|
||||
ENTRY(__VA_ARGS__, vkGetDeviceProcAddr); \
|
||||
|
||||
#define SURFACE_INSTANCE_FUNCTION_TABLE(ENTRY, ...) \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceSurfaceCapabilitiesKHR); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceSurfaceFormatsKHR); \
|
||||
ENTRY(__VA_ARGS__, vkGetPhysicalDeviceSurfacePresentModesKHR); \
|
||||
ENTRY(__VA_ARGS__, vkDestroySurfaceKHR); \
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define DEBUG_INSTANCE_FUNCTION_TABLE(ENTRY, ...) \
|
||||
ENTRY(__VA_ARGS__, vkCreateDebugUtilsMessengerEXT); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyDebugUtilsMessengerEXT);
|
||||
#else
|
||||
#define DEBUG_INSTANCE_FUNCTION_TABLE(ENTRY, ...)
|
||||
#endif
|
||||
|
||||
// Device functions.
|
||||
#define DEVICE_FUNCTION_TABLE(ENTRY, ...) \
|
||||
ENTRY(__VA_ARGS__, vkDestroyDevice); \
|
||||
ENTRY(__VA_ARGS__, vkCreateShaderModule); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyShaderModule); \
|
||||
ENTRY(__VA_ARGS__, vkCreatePipelineLayout); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyPipelineLayout); \
|
||||
ENTRY(__VA_ARGS__, vkCreateGraphicsPipelines); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyPipeline); \
|
||||
ENTRY(__VA_ARGS__, vkCreateImageView); \
|
||||
ENTRY(__VA_ARGS__, vkCreateFramebuffer); \
|
||||
ENTRY(__VA_ARGS__, vkCreateCommandPool); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyCommandPool); \
|
||||
ENTRY(__VA_ARGS__, vkAllocateCommandBuffers); \
|
||||
ENTRY(__VA_ARGS__, vkFreeCommandBuffers); \
|
||||
ENTRY(__VA_ARGS__, vkCreateSemaphore); \
|
||||
ENTRY(__VA_ARGS__, vkDestroySemaphore); \
|
||||
ENTRY(__VA_ARGS__, vkWaitSemaphores); \
|
||||
ENTRY(__VA_ARGS__, vkGetSemaphoreCounterValue); \
|
||||
ENTRY(__VA_ARGS__, vkCreateFence); \
|
||||
ENTRY(__VA_ARGS__, vkGetDeviceQueue); \
|
||||
ENTRY(__VA_ARGS__, vkWaitForFences); \
|
||||
ENTRY(__VA_ARGS__, vkResetFences); \
|
||||
ENTRY(__VA_ARGS__, vkResetCommandBuffer); \
|
||||
ENTRY(__VA_ARGS__, vkQueueSubmit); \
|
||||
ENTRY(__VA_ARGS__, vkQueueWaitIdle); \
|
||||
ENTRY(__VA_ARGS__, vkBeginCommandBuffer); \
|
||||
ENTRY(__VA_ARGS__, vkCmdBlitImage); \
|
||||
ENTRY(__VA_ARGS__, vkCmdPipelineBarrier); \
|
||||
ENTRY(__VA_ARGS__, vkCmdBeginRenderPass); \
|
||||
ENTRY(__VA_ARGS__, vkCmdExecuteCommands); \
|
||||
ENTRY(__VA_ARGS__, vkCmdClearAttachments); \
|
||||
ENTRY(__VA_ARGS__, vkCmdBindPipeline); \
|
||||
ENTRY(__VA_ARGS__, vkCmdSetViewport); \
|
||||
ENTRY(__VA_ARGS__, vkCmdSetScissor); \
|
||||
ENTRY(__VA_ARGS__, vkCmdDraw); \
|
||||
ENTRY(__VA_ARGS__, vkCmdEndRenderPass); \
|
||||
ENTRY(__VA_ARGS__, vkEndCommandBuffer); \
|
||||
ENTRY(__VA_ARGS__, vkCreateImage); \
|
||||
ENTRY(__VA_ARGS__, vkCreateSampler); \
|
||||
ENTRY(__VA_ARGS__, vkDestroySampler); \
|
||||
ENTRY(__VA_ARGS__, vkAllocateMemory); \
|
||||
ENTRY(__VA_ARGS__, vkBindImageMemory); \
|
||||
ENTRY(__VA_ARGS__, vkCreateDescriptorSetLayout); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyDescriptorSetLayout); \
|
||||
ENTRY(__VA_ARGS__, vkUpdateDescriptorSets); \
|
||||
ENTRY(__VA_ARGS__, vkCreateDescriptorPool); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyDescriptorPool); \
|
||||
ENTRY(__VA_ARGS__, vkAllocateDescriptorSets); \
|
||||
ENTRY(__VA_ARGS__, vkFreeDescriptorSets); \
|
||||
ENTRY(__VA_ARGS__, vkCmdBindDescriptorSets); \
|
||||
ENTRY(__VA_ARGS__, vkGetImageMemoryRequirements2); \
|
||||
ENTRY(__VA_ARGS__, vkCreateBuffer); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyBuffer); \
|
||||
ENTRY(__VA_ARGS__, vkCreateBufferView); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyBufferView); \
|
||||
ENTRY(__VA_ARGS__, vkGetBufferMemoryRequirements2); \
|
||||
ENTRY(__VA_ARGS__, vkBindBufferMemory); \
|
||||
ENTRY(__VA_ARGS__, vkMapMemory); \
|
||||
ENTRY(__VA_ARGS__, vkUnmapMemory); \
|
||||
ENTRY(__VA_ARGS__, vkCmdBindVertexBuffers); \
|
||||
ENTRY(__VA_ARGS__, vkCreateRenderPass); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyRenderPass); \
|
||||
ENTRY(__VA_ARGS__, vkFreeMemory); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyImageView); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyImage); \
|
||||
ENTRY(__VA_ARGS__, vkDestroyFramebuffer); \
|
||||
ENTRY(__VA_ARGS__, vkFlushMappedMemoryRanges); \
|
||||
ENTRY(__VA_ARGS__, vkInvalidateMappedMemoryRanges); \
|
||||
ENTRY(__VA_ARGS__, vkCmdPushConstants); \
|
||||
ENTRY(__VA_ARGS__, vkCmdCopyBufferToImage); \
|
||||
ENTRY(__VA_ARGS__, vkCmdCopyImageToBuffer); \
|
||||
ENTRY(__VA_ARGS__, vkCmdCopyBuffer); \
|
||||
|
||||
#define SWAPCHAIN_DEVICE_FUNCTION_TABLE(ENTRY, ...) \
|
||||
ENTRY(__VA_ARGS__, vkCreateSwapchainKHR); \
|
||||
ENTRY(__VA_ARGS__, vkDestroySwapchainKHR); \
|
||||
ENTRY(__VA_ARGS__, vkGetSwapchainImagesKHR); \
|
||||
ENTRY(__VA_ARGS__, vkAcquireNextImageKHR); \
|
||||
ENTRY(__VA_ARGS__, vkQueuePresentKHR); \
|
||||
|
||||
// Utilities for working with function pointers.
|
||||
|
||||
#define DECL_PFN(_, NAME) PFN_ ## NAME NAME
|
||||
#define GET_PROC_ADDR(GETPROCADDR, HANDLE, PREFIX, NAME) ((PREFIX NAME) = (PFN_ ## NAME) GETPROCADDR(HANDLE, #NAME))
|
||||
#define CHECK_PROC_ADDR(MISSING_FLAG, ...) if (GET_PROC_ADDR(__VA_ARGS__) == NULL) (MISSING_FLAG = VK_TRUE)
|
||||
#define LOG_MISSING_PFN(PREFIX, NAME) if ((PREFIX NAME) == NULL) J2dRlsTraceLn(J2D_TRACE_ERROR, " " #NAME)
|
||||
|
||||
#endif //VKFunctionTable_h_Included
|
||||
@@ -27,35 +27,38 @@
|
||||
#include <assert.h>
|
||||
#include "VKUtil.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKDevice.h"
|
||||
#include "VKImage.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKSurfaceData.h"
|
||||
|
||||
static size_t viewKeyHash(const void* ptr) {
|
||||
const VKImageViewKey* k = ptr;
|
||||
return (size_t) k->format | ((size_t) k->swizzle << 32);
|
||||
}
|
||||
static bool viewKeyEquals(const void* ap, const void* bp) {
|
||||
const VKImageViewKey *a = ap, *b = bp;
|
||||
return a->format == b->format && a->swizzle == b->swizzle;
|
||||
}
|
||||
|
||||
static VkBool32 VKImage_CreateView(VKDevice* device, VKImage* image) {
|
||||
static VkImageView VKImage_CreateView(VKDevice* device, VkImage image, VkFormat format, VkComponentMapping swizzle) {
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = image->handle,
|
||||
.image = image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = image->format,
|
||||
.subresourceRange.aspectMask = VKImage_GetAspect(image),
|
||||
.format = format,
|
||||
.components = swizzle,
|
||||
.subresourceRange.aspectMask = VKUtil_GetFormatGroup(format).aspect,
|
||||
.subresourceRange.baseMipLevel = 0,
|
||||
.subresourceRange.levelCount = 1,
|
||||
.subresourceRange.baseArrayLayer = 0,
|
||||
.subresourceRange.layerCount = 1,
|
||||
};
|
||||
|
||||
VK_IF_ERROR(device->vkCreateImageView(device->handle, &viewInfo, NULL, &image->view)) {
|
||||
return VK_FALSE;
|
||||
VkImageView view;
|
||||
VK_IF_ERROR(device->vkCreateImageView(device->handle, &viewInfo, NULL, &view)) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
VkImageAspectFlagBits VKImage_GetAspect(VKImage* image) {
|
||||
return VKUtil_GetFormatGroup(image->format).bytes == 0 ? // Unknown format group means stencil.
|
||||
VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
return view;
|
||||
}
|
||||
|
||||
VKImage* VKImage_Create(VKDevice* device, uint32_t width, uint32_t height,
|
||||
@@ -106,10 +109,7 @@ VKImage* VKImage_Create(VKDevice* device, uint32_t width, uint32_t height,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!VKImage_CreateView(device, image)) {
|
||||
VKImage_Destroy(device, image);
|
||||
return NULL;
|
||||
}
|
||||
HASH_MAP_REHASH(image->viewMap, linear_probing, &viewKeyEquals, &viewKeyHash, 1, 10, 0.75);
|
||||
|
||||
return image;
|
||||
}
|
||||
@@ -142,8 +142,78 @@ void VKImage_LoadBuffer(VKDevice* device, VKImage* image, VKBuffer* buffer,
|
||||
void VKImage_Destroy(VKDevice* device, VKImage* image) {
|
||||
assert(device != NULL && device->allocator != NULL);
|
||||
if (image == NULL) return;
|
||||
device->vkDestroyImageView(device->handle, image->view, NULL);
|
||||
if (image->viewMap != NULL) {
|
||||
for (const VKImageViewKey* k = NULL; (k = MAP_NEXT_KEY(image->viewMap, k)) != NULL;) {
|
||||
const VKImageViewInfo* viewInfo = MAP_FIND(image->viewMap, *k);
|
||||
if (viewInfo->descriptorSet != VK_NULL_HANDLE) {
|
||||
device->vkFreeDescriptorSets(device->handle, viewInfo->descriptorPool, 1, &viewInfo->descriptorSet);
|
||||
}
|
||||
device->vkDestroyImageView(device->handle, viewInfo->view, NULL);
|
||||
}
|
||||
MAP_FREE(image->viewMap);
|
||||
}
|
||||
device->vkDestroyImage(device->handle, image->handle, NULL);
|
||||
VKAllocator_Free(device->allocator, image->memory);
|
||||
free(image);
|
||||
}
|
||||
|
||||
static VKImageViewInfo* VKImage_GetViewInfo(VKDevice* device, VKImage* image, VkFormat format, VKPackedSwizzle swizzle) {
|
||||
VKImageViewKey key = { format, swizzle };
|
||||
VKImageViewInfo* viewInfo = MAP_FIND(image->viewMap, key);
|
||||
if (viewInfo == NULL || viewInfo->view == VK_NULL_HANDLE) {
|
||||
if (viewInfo == NULL) viewInfo = &MAP_AT(image->viewMap, key);
|
||||
viewInfo->view = VKImage_CreateView(device, image->handle, format, VK_UNPACK_SWIZZLE(swizzle));
|
||||
}
|
||||
return viewInfo;
|
||||
}
|
||||
|
||||
VkImageView VKImage_GetView(VKDevice* device, VKImage* image, VkFormat format, VKPackedSwizzle swizzle) {
|
||||
return VKImage_GetViewInfo(device, image, format, swizzle)->view;
|
||||
}
|
||||
|
||||
VkDescriptorSet VKImage_GetDescriptorSet(VKDevice* device, VKImage* image, VkFormat format, VKPackedSwizzle swizzle) {
|
||||
VKImageViewInfo* info = VKImage_GetViewInfo(device, image, format, swizzle);
|
||||
if (info->descriptorSet == VK_NULL_HANDLE) {
|
||||
VKRenderer_CreateImageDescriptorSet(device->renderer, &info->descriptorPool, &info->descriptorSet);
|
||||
VkDescriptorImageInfo imageInfo = {
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.imageView = info->view
|
||||
};
|
||||
VkWriteDescriptorSet descriptorWrites = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = info->descriptorSet,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
.descriptorCount = 1,
|
||||
.pImageInfo = &imageInfo
|
||||
};
|
||||
device->vkUpdateDescriptorSets(device->handle, 1, &descriptorWrites, 0, NULL);
|
||||
}
|
||||
return info->descriptorSet;
|
||||
}
|
||||
|
||||
void VKImage_AddBarrier(VkImageMemoryBarrier* barriers, VKBarrierBatch* batch,
|
||||
VKImage* image, VkPipelineStageFlags stage, VkAccessFlags access, VkImageLayout layout) {
|
||||
assert(barriers != NULL && batch != NULL && image != NULL);
|
||||
// TODO Even if stage, access and layout didn't change, we may still need a barrier against WaW hazard.
|
||||
if (stage != image->lastStage || access != image->lastAccess || layout != image->layout) {
|
||||
barriers[batch->barrierCount] = (VkImageMemoryBarrier) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = image->lastAccess,
|
||||
.dstAccessMask = access,
|
||||
.oldLayout = image->layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image->handle,
|
||||
.subresourceRange = { VKUtil_GetFormatGroup(image->format).aspect, 0, 1, 0, 1 }
|
||||
};
|
||||
batch->barrierCount++;
|
||||
batch->srcStages |= image->lastStage;
|
||||
batch->dstStages |= stage;
|
||||
image->lastStage = stage;
|
||||
image->lastAccess = access;
|
||||
image->layout = layout;
|
||||
}
|
||||
}
|
||||
@@ -27,23 +27,33 @@
|
||||
#ifndef VKImage_h_Included
|
||||
#define VKImage_h_Included
|
||||
|
||||
#include "VKTypes.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKUtil.h"
|
||||
|
||||
typedef struct {
|
||||
VkFormat format;
|
||||
VKPackedSwizzle swizzle;
|
||||
} VKImageViewKey;
|
||||
|
||||
typedef struct {
|
||||
VkImageView view;
|
||||
VkDescriptorSet descriptorSet;
|
||||
VkDescriptorPool descriptorPool; // Non-owning.
|
||||
} VKImageViewInfo;
|
||||
|
||||
struct VKImage {
|
||||
VkImage handle;
|
||||
VKMemory memory;
|
||||
VkImageView view;
|
||||
VkFormat format;
|
||||
VkExtent2D extent;
|
||||
VkImage handle;
|
||||
VKMemory memory;
|
||||
VkFormat format;
|
||||
VkExtent2D extent;
|
||||
MAP(VKImageViewKey, VKImageViewInfo) viewMap;
|
||||
|
||||
|
||||
VkImageLayout layout;
|
||||
VkPipelineStageFlagBits lastStage;
|
||||
VkAccessFlagBits lastAccess;
|
||||
};
|
||||
|
||||
VkImageAspectFlagBits VKImage_GetAspect(VKImage* image);
|
||||
|
||||
VKImage* VKImage_Create(VKDevice* device, uint32_t width, uint32_t height,
|
||||
VkImageCreateFlags flags, VkFormat format,
|
||||
VkImageTiling tiling, VkImageUsageFlags usage, VkSampleCountFlagBits samples,
|
||||
@@ -53,4 +63,12 @@ void VKImage_LoadBuffer(VKDevice* device, VKImage* image, VKBuffer* buffer,
|
||||
uint32_t x0, uint32_t y0, uint32_t width, uint32_t height);
|
||||
|
||||
void VKImage_Destroy(VKDevice* device, VKImage* image);
|
||||
|
||||
VkImageView VKImage_GetView(VKDevice* device, VKImage* image, VkFormat format, VKPackedSwizzle swizzle);
|
||||
|
||||
VkDescriptorSet VKImage_GetDescriptorSet(VKDevice* device, VKImage* image, VkFormat format, VKPackedSwizzle swizzle);
|
||||
|
||||
void VKImage_AddBarrier(VkImageMemoryBarrier* barriers, VKBarrierBatch* batch,
|
||||
VKImage* image, VkPipelineStageFlags stage, VkAccessFlags access, VkImageLayout layout);
|
||||
|
||||
#endif // VKImage_h_Included
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
// questions.
|
||||
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKEnv.h"
|
||||
#include "VKPipelines.h"
|
||||
|
||||
#define INCLUDE_BYTECODE
|
||||
@@ -44,6 +44,8 @@ static size_t pipelineDescriptorHash(const void* ptr) {
|
||||
const VKPipelineDescriptor* d = ptr;
|
||||
uint32_t h = 0U;
|
||||
hash(&h, d->stencilMode);
|
||||
hash(&h, d->dstOpaque);
|
||||
hash(&h, d->inAlphaType);
|
||||
hash(&h, d->composite);
|
||||
hash(&h, d->shader);
|
||||
hash(&h, d->topology);
|
||||
@@ -52,6 +54,8 @@ static size_t pipelineDescriptorHash(const void* ptr) {
|
||||
static bool pipelineDescriptorEquals(const void* ap, const void* bp) {
|
||||
const VKPipelineDescriptor *a = ap, *b = bp;
|
||||
return a->stencilMode == b->stencilMode &&
|
||||
a->dstOpaque == b->dstOpaque &&
|
||||
a->inAlphaType == b->inAlphaType &&
|
||||
a->composite == b->composite &&
|
||||
a->shader == b->shader &&
|
||||
a->topology == b->topology;
|
||||
@@ -123,31 +127,49 @@ for (uint32_t i = 0; i < SARRAY_COUNT_OF(INPUT_STATE_ATTRIBUTES_##NAME); i++) {
|
||||
VKUtil_GetFormatGroup(INPUT_STATE_ATTRIBUTE_FORMATS_##NAME[i]).bytes; \
|
||||
} if (sizeof(TYPE) != INPUT_STATE_BINDING_SIZE_##NAME) VK_FATAL_ERROR("Vertex size mismatch for input state " #NAME)
|
||||
|
||||
static VkPipeline VKPipelines_CreatePipelines(VKRenderPassContext* renderPassContext, uint32_t count,
|
||||
const VKPipelineDescriptor* descriptors) {
|
||||
static VKPipelineInfo VKPipelines_CreatePipelines(VKRenderPassContext* renderPassContext, uint32_t count,
|
||||
const VKPipelineDescriptor* descriptors) {
|
||||
assert(renderPassContext != NULL && renderPassContext->pipelineContext != NULL);
|
||||
assert(count > 0 && descriptors != NULL);
|
||||
VKPipelineContext* pipelineContext = renderPassContext->pipelineContext;
|
||||
VKDevice* device = pipelineContext->device;
|
||||
VKShaders* shaders = pipelineContext->shaders;
|
||||
VKComposites* composites = &VKGE_graphics_environment()->composites;
|
||||
VKComposites* composites = &VKEnv_GetInstance()->composites;
|
||||
|
||||
VKPipelineInfo pipelineInfos[count];
|
||||
// Setup pipeline creation structs.
|
||||
static const uint32_t MAX_DYNAMIC_STATES = 2;
|
||||
typedef struct {
|
||||
VkPipelineShaderStageCreateInfo createInfos[2]; // vert + frag
|
||||
} ShaderStages;
|
||||
ShaderStages stages[count];
|
||||
typedef struct {
|
||||
VkSpecializationInfo info;
|
||||
VkSpecializationMapEntry entries[2];
|
||||
uint64_t data[1];
|
||||
} Specialization;
|
||||
Specialization specializations[count][2];
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStates[count];
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilStates[count];
|
||||
VkPipelineDynamicStateCreateInfo dynamicStates[count];
|
||||
VkDynamicState dynamicStateValues[count][MAX_DYNAMIC_STATES];
|
||||
VkGraphicsPipelineCreateInfo createInfos[count];
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const VKCompositeState* compositeState =
|
||||
VKComposites_GetState(composites, descriptors[i].composite, descriptors[i].dstOpaque);
|
||||
pipelineInfos[i].outAlphaType = compositeState->outAlphaType;
|
||||
// Init default pipeline state. Some members are left uninitialized:
|
||||
// - pStages (but stageCount is set to 2)
|
||||
// - pVertexInputState
|
||||
// - createInfo.layout
|
||||
for (uint32_t j = 0; j < SARRAY_COUNT_OF(specializations[i]); j++) {
|
||||
specializations[i][j].info = (VkSpecializationInfo) {
|
||||
.mapEntryCount = 0,
|
||||
.pMapEntries = specializations[i][j].entries,
|
||||
.dataSize = 0,
|
||||
.pData = specializations[i][j].data
|
||||
};
|
||||
}
|
||||
inputAssemblyStates[i] = (VkPipelineInputAssemblyStateCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = descriptors[i].topology
|
||||
@@ -201,7 +223,7 @@ static VkPipeline VKPipelines_CreatePipelines(VKRenderPassContext* renderPassCon
|
||||
.pRasterizationState = &rasterizationState,
|
||||
.pMultisampleState = &multisampleState,
|
||||
.pDepthStencilState = &depthStencilStates[i],
|
||||
.pColorBlendState = &VKComposites_GetState(composites, descriptors[i].composite)->blendState,
|
||||
.pColorBlendState = &compositeState->blendState,
|
||||
.pDynamicState = &dynamicStates[i],
|
||||
.renderPass = renderPassContext->renderPass[descriptors[i].stencilMode != STENCIL_MODE_NONE],
|
||||
.subpass = 0,
|
||||
@@ -233,6 +255,15 @@ static VkPipeline VKPipelines_CreatePipelines(VKRenderPassContext* renderPassCon
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_BLIT;
|
||||
createInfos[i].layout = pipelineContext->texturePipelineLayout;
|
||||
stages[i] = (ShaderStages) {{ shaders->blit_vert, shaders->blit_frag }};
|
||||
// Alpha conversion specialization.
|
||||
uint32_t* spec = (uint32_t*) specializations[i][1].data;
|
||||
spec[0] = descriptors[i].inAlphaType;
|
||||
spec[1] = pipelineInfos[i].outAlphaType;
|
||||
specializations[i][1].info.dataSize = 8;
|
||||
specializations[i][1].entries[0] = (VkSpecializationMapEntry) { 0, 0, 4 };
|
||||
specializations[i][1].entries[1] = (VkSpecializationMapEntry) { 1, 4, 4 };
|
||||
specializations[i][1].info.mapEntryCount = 2;
|
||||
stages[i].createInfos[1].pSpecializationInfo = &specializations[i][1].info;
|
||||
break;
|
||||
case SHADER_CLIP:
|
||||
createInfos[i].pVertexInputState = &INPUT_STATE_CLIP;
|
||||
@@ -259,8 +290,8 @@ static VkPipeline VKPipelines_CreatePipelines(VKRenderPassContext* renderPassCon
|
||||
VK_FATAL_ERROR("Cannot create pipeline, unknown shader requested!");
|
||||
}
|
||||
assert(createInfos[i].pDynamicState->dynamicStateCount <= MAX_DYNAMIC_STATES);
|
||||
J2dRlsTraceLn4(J2D_TRACE_INFO, "VKPipelines_CreatePipelines: stencilMode=%d, composite=%d, shader=%d, topology=%d",
|
||||
descriptors[i].stencilMode, descriptors[i].composite, descriptors[i].shader, descriptors[i].topology);
|
||||
J2dRlsTraceLn5(J2D_TRACE_INFO, "VKPipelines_CreatePipelines: stencilMode=%d, dstOpaque=%d, composite=%d, shader=%d, topology=%d",
|
||||
descriptors[i].stencilMode, descriptors[i].dstOpaque, descriptors[i].composite, descriptors[i].shader, descriptors[i].topology);
|
||||
}
|
||||
|
||||
// Create pipelines.
|
||||
@@ -269,8 +300,11 @@ static VkPipeline VKPipelines_CreatePipelines(VKRenderPassContext* renderPassCon
|
||||
VK_IF_ERROR(device->vkCreateGraphicsPipelines(device->handle, VK_NULL_HANDLE, count,
|
||||
createInfos, NULL, pipelines)) VK_UNHANDLED_ERROR();
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKPipelines_CreatePipelines: created %d pipelines", count);
|
||||
for (uint32_t i = 0; i < count; ++i) MAP_AT(renderPassContext->pipelines, descriptors[i]) = pipelines[i];
|
||||
return pipelines[0];
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
pipelineInfos[i].pipeline = pipelines[i];
|
||||
MAP_AT(renderPassContext->pipelines, descriptors[i]) = pipelineInfos[i];
|
||||
}
|
||||
return pipelineInfos[0];
|
||||
}
|
||||
|
||||
static VkResult VKPipelines_InitRenderPasses(VKDevice* device, VKRenderPassContext* renderPassContext) {
|
||||
@@ -332,8 +366,8 @@ static void VKPipelines_DestroyRenderPassContext(VKRenderPassContext* renderPass
|
||||
VKDevice* device = renderPassContext->pipelineContext->device;
|
||||
assert(device != NULL);
|
||||
for (const VKPipelineDescriptor* k = NULL; (k = MAP_NEXT_KEY(renderPassContext->pipelines, k)) != NULL;) {
|
||||
VkPipeline pipeline = *MAP_FIND(renderPassContext->pipelines, *k);
|
||||
device->vkDestroyPipeline(device->handle, pipeline, NULL);
|
||||
const VKPipelineInfo* info = MAP_FIND(renderPassContext->pipelines, *k);
|
||||
device->vkDestroyPipeline(device->handle, info->pipeline, NULL);
|
||||
}
|
||||
MAP_FREE(renderPassContext->pipelines);
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
@@ -372,7 +406,7 @@ static VkResult VKPipelines_InitPipelineLayouts(VKDevice* device, VKPipelineCont
|
||||
VkPushConstantRange pushConstantRange = {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(float) * 2
|
||||
.size = sizeof(VKTransform)
|
||||
};
|
||||
VkPipelineLayoutCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
@@ -385,7 +419,7 @@ static VkResult VKPipelines_InitPipelineLayouts(VKDevice* device, VKPipelineCont
|
||||
|
||||
VkDescriptorSetLayoutBinding textureLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.pImmutableSamplers = NULL
|
||||
@@ -398,8 +432,12 @@ static VkResult VKPipelines_InitPipelineLayouts(VKDevice* device, VKPipelineCont
|
||||
result = device->vkCreateDescriptorSetLayout(device->handle, &textureDescriptorSetLayoutCreateInfo, NULL, &pipelines->textureDescriptorSetLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
createInfo.setLayoutCount = 1;
|
||||
createInfo.pSetLayouts = &pipelines->textureDescriptorSetLayout;
|
||||
VkDescriptorSetLayout textureDescriptorSetLayouts[] = {
|
||||
pipelines->textureDescriptorSetLayout,
|
||||
pipelines->samplers.descriptorSetLayout
|
||||
};
|
||||
createInfo.setLayoutCount = 2;
|
||||
createInfo.pSetLayouts = textureDescriptorSetLayouts;
|
||||
result = device->vkCreatePipelineLayout(device->handle, &createInfo, NULL, &pipelines->texturePipelineLayout);
|
||||
VK_IF_ERROR(result) return result;
|
||||
|
||||
@@ -432,6 +470,12 @@ VKPipelineContext* VKPipelines_CreateContext(VKDevice* device) {
|
||||
VK_RUNTIME_ASSERT(pipelineContext);
|
||||
pipelineContext->device = device;
|
||||
|
||||
pipelineContext->samplers = VKSamplers_Create(device);
|
||||
if (pipelineContext->samplers.descriptorPool == VK_NULL_HANDLE) {
|
||||
VKPipelines_DestroyContext(pipelineContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pipelineContext->shaders = VKPipelines_CreateShaders(device);
|
||||
if (pipelineContext->shaders == NULL) {
|
||||
VKPipelines_DestroyContext(pipelineContext);
|
||||
@@ -443,20 +487,6 @@ VKPipelineContext* VKPipelines_CreateContext(VKDevice* device) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create sampler.
|
||||
VkSamplerCreateInfo samplerCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = VK_FILTER_LINEAR,
|
||||
.minFilter = VK_FILTER_LINEAR,
|
||||
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT
|
||||
};
|
||||
VK_IF_ERROR(device->vkCreateSampler(device->handle, &samplerCreateInfo, NULL, &pipelineContext->linearRepeatSampler)) {
|
||||
VKPipelines_DestroyContext(pipelineContext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKPipelines_CreateContext(%p)", pipelineContext);
|
||||
return pipelineContext;
|
||||
}
|
||||
@@ -472,7 +502,6 @@ void VKPipelines_DestroyContext(VKPipelineContext* pipelineContext) {
|
||||
ARRAY_FREE(pipelineContext->renderPassContexts);
|
||||
|
||||
VKPipelines_DestroyShaders(device, pipelineContext->shaders);
|
||||
device->vkDestroySampler(device->handle, pipelineContext->linearRepeatSampler, NULL);
|
||||
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->colorPipelineLayout, NULL);
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->texturePipelineLayout, NULL);
|
||||
@@ -480,6 +509,8 @@ void VKPipelines_DestroyContext(VKPipelineContext* pipelineContext) {
|
||||
device->vkDestroyPipelineLayout(device->handle, pipelineContext->maskFillPipelineLayout, NULL);
|
||||
device->vkDestroyDescriptorSetLayout(device->handle, pipelineContext->maskFillDescriptorSetLayout, NULL);
|
||||
|
||||
VKSamplers_Destroy(device, pipelineContext->samplers);
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKPipelines_DestroyContext(%p)", pipelineContext);
|
||||
free(pipelineContext);
|
||||
}
|
||||
@@ -497,11 +528,13 @@ VKRenderPassContext* VKPipelines_GetRenderPassContext(VKPipelineContext* pipelin
|
||||
return renderPassContext;
|
||||
}
|
||||
|
||||
VkPipeline VKPipelines_GetPipeline(VKRenderPassContext* renderPassContext, VKPipelineDescriptor descriptor) {
|
||||
// static VKPipelineInfo VKPipelines_
|
||||
|
||||
VKPipelineInfo VKPipelines_GetPipelineInfo(VKRenderPassContext* renderPassContext, VKPipelineDescriptor descriptor) {
|
||||
assert(renderPassContext != NULL);
|
||||
VkPipeline pipeline = MAP_AT(renderPassContext->pipelines, descriptor);
|
||||
if (pipeline == VK_NULL_HANDLE) {
|
||||
pipeline = VKPipelines_CreatePipelines(renderPassContext, 1, &descriptor);
|
||||
VKPipelineInfo info = MAP_AT(renderPassContext->pipelines, descriptor);
|
||||
if (info.pipeline == VK_NULL_HANDLE) {
|
||||
info = VKPipelines_CreatePipelines(renderPassContext, 1, &descriptor);
|
||||
}
|
||||
return pipeline;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#define VKPipelines_h_Included
|
||||
|
||||
#include "VKComposites.h"
|
||||
#include "VKSamplers.h"
|
||||
#include "VKTypes.h"
|
||||
#include "VKUtil.h"
|
||||
|
||||
@@ -53,12 +54,19 @@ typedef enum {
|
||||
* When adding new fields, update hash and comparison in VKPipelines.c.
|
||||
*/
|
||||
typedef struct {
|
||||
VKStencilMode stencilMode;
|
||||
VKStencilMode stencilMode : 2;
|
||||
VkBool32 dstOpaque : 1;
|
||||
AlphaType inAlphaType : 1;
|
||||
VKCompositeMode composite;
|
||||
VKShader shader;
|
||||
VkPrimitiveTopology topology;
|
||||
} VKPipelineDescriptor;
|
||||
|
||||
typedef struct {
|
||||
VkPipeline pipeline;
|
||||
AlphaType outAlphaType;
|
||||
} VKPipelineInfo;
|
||||
|
||||
/**
|
||||
* Global pipeline context.
|
||||
*/
|
||||
@@ -70,8 +78,7 @@ struct VKPipelineContext {
|
||||
VkDescriptorSetLayout maskFillDescriptorSetLayout;
|
||||
VkPipelineLayout maskFillPipelineLayout;
|
||||
|
||||
VkSampler linearRepeatSampler;
|
||||
|
||||
VKSamplers samplers;
|
||||
struct VKShaders* shaders;
|
||||
ARRAY(VKRenderPassContext*) renderPassContexts;
|
||||
};
|
||||
@@ -80,10 +87,10 @@ struct VKPipelineContext {
|
||||
* Per-format context.
|
||||
*/
|
||||
struct VKRenderPassContext {
|
||||
VKPipelineContext* pipelineContext;
|
||||
VkFormat format;
|
||||
VkRenderPass renderPass[2]; // Color-only and color+stencil.
|
||||
MAP(VKPipelineDescriptor, VkPipeline) pipelines;
|
||||
VKPipelineContext* pipelineContext;
|
||||
VkFormat format;
|
||||
VkRenderPass renderPass[2]; // Color-only and color+stencil.
|
||||
MAP(VKPipelineDescriptor, VKPipelineInfo) pipelines;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -92,7 +99,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
float x, y;
|
||||
Color color;
|
||||
RGBA color;
|
||||
} VKColorVertex;
|
||||
|
||||
typedef struct {
|
||||
@@ -102,13 +109,13 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
int x, y, maskOffset, maskScanline;
|
||||
Color color;
|
||||
RGBA color;
|
||||
} VKMaskFillColorVertex;
|
||||
|
||||
VKPipelineContext* VKPipelines_CreateContext(VKDevice* device);
|
||||
void VKPipelines_DestroyContext(VKPipelineContext* pipelines);
|
||||
|
||||
VKRenderPassContext* VKPipelines_GetRenderPassContext(VKPipelineContext* pipelineContext, VkFormat format);
|
||||
VkPipeline VKPipelines_GetPipeline(VKRenderPassContext* renderPassContext, VKPipelineDescriptor descriptor);
|
||||
VKPipelineInfo VKPipelines_GetPipelineInfo(VKRenderPassContext* renderPassContext, VKPipelineDescriptor descriptor);
|
||||
|
||||
#endif //VKPipelines_h_Included
|
||||
|
||||
@@ -24,18 +24,17 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include "sun_font_StrikeCache.h"
|
||||
#include "sun_java2d_pipe_BufferedOpCodes.h"
|
||||
#include "sun_java2d_pipe_BufferedRenderPipe.h"
|
||||
#include "sun_java2d_pipe_BufferedTextPipe.h"
|
||||
#include "sun_java2d_vulkan_VKBlitLoops.h"
|
||||
#include "fontscalerdefs.h"
|
||||
#include "Trace.h"
|
||||
#include "jlong.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKBlitLoops.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKEnv.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKUtil.h"
|
||||
|
||||
@@ -50,7 +49,8 @@
|
||||
#define NEXT_BOOLEAN(buf) (jboolean)NEXT_INT(buf)
|
||||
#define NEXT_LONG(buf) NEXT_VAL(buf, jlong)
|
||||
#define NEXT_DOUBLE(buf) NEXT_VAL(buf, jdouble)
|
||||
#define NEXT_SURFACE(buf) ((VKSDOps*) (SurfaceDataOps*) jlong_to_ptr(NEXT_LONG(buf)))
|
||||
#define NEXT_SURFACE(buf) ((SurfaceDataOps*) jlong_to_ptr(NEXT_LONG(buf)))
|
||||
#define NEXT_VK_SURFACE(buf) ((VKSDOps*) NEXT_SURFACE(buf))
|
||||
|
||||
/*
|
||||
* Increments a pointer (buf) by the given number of bytes.
|
||||
@@ -64,6 +64,8 @@
|
||||
(((packedval) >> (offset)) & (mask))
|
||||
#define EXTRACT_BYTE(packedval, offset) \
|
||||
(unsigned char)EXTRACT_VAL(packedval, offset, 0xff)
|
||||
#define EXTRACT_SHORT(packedval, offset) \
|
||||
(jshort)EXTRACT_VAL(packedval, offset, 0xffff)
|
||||
#define EXTRACT_BOOLEAN(packedval, offset) \
|
||||
(jboolean)EXTRACT_VAL(packedval, offset, 0x1)
|
||||
|
||||
@@ -88,31 +90,9 @@
|
||||
|
||||
#define OFFSET_SRCTYPE sun_java2d_vulkan_VKBlitLoops_OFFSET_SRCTYPE
|
||||
#define OFFSET_HINT sun_java2d_vulkan_VKBlitLoops_OFFSET_HINT
|
||||
#define OFFSET_TEXTURE sun_java2d_vulkan_VKBlitLoops_OFFSET_TEXTURE
|
||||
#define OFFSET_RTT sun_java2d_vulkan_VKBlitLoops_OFFSET_RTT
|
||||
#define OFFSET_XFORM sun_java2d_vulkan_VKBlitLoops_OFFSET_XFORM
|
||||
#define OFFSET_ISOBLIT sun_java2d_vulkan_VKBlitLoops_OFFSET_ISOBLIT
|
||||
|
||||
#define NO_CLIP ((VkRect2D) {{0, 0}, {0x7FFFFFFFU, 0x7FFFFFFFU}})
|
||||
|
||||
// Rendering context is only accessed from VKRenderQueue_flushBuffer,
|
||||
// which is only called from queue flusher thread, no need for synchronization.
|
||||
static VKRenderingContext context = {
|
||||
.surface = NULL,
|
||||
.transform = {1.0, 0.0, 0.0,0.0, 1.0, 0.0},
|
||||
.color = {},
|
||||
.composite = ALPHA_COMPOSITE_SRC_OVER,
|
||||
.extraAlpha = 1.0f,
|
||||
.clipModCount = 1,
|
||||
.clipRect = NO_CLIP,
|
||||
.clipSpanVertices = NULL
|
||||
};
|
||||
// We keep this color separately from context.color,
|
||||
// because we need consistent state when switching between XOR and alpha composite modes.
|
||||
// This variable holds last value set by SET_COLOR, while context.color holds color,
|
||||
// currently used for drawing, which may have also been provided by SET_XOR_COMPOSITE.
|
||||
Color color;
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
(JNIEnv *env, jobject oglrq, jlong buf, jint limit)
|
||||
{
|
||||
@@ -162,7 +142,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DRAW_RECT(%d, %d, %d, %d)",
|
||||
x, y, w, h);
|
||||
VKRenderer_RenderRect(&context, VK_FALSE, x, y, w, h);
|
||||
VKRenderer_RenderRect(VK_FALSE, x, y, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
|
||||
@@ -204,7 +184,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn8(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DRAW_PARALLELOGRAM(%f, %f, %f, %f, %f, %f, %f, %f)",
|
||||
x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12);
|
||||
VKRenderer_RenderParallelogram(&context, VK_FALSE, x11, y11, dx21, dy21, dx12, dy12);
|
||||
VKRenderer_RenderParallelogram(VK_FALSE, x11, y11, dx21, dy21,
|
||||
dx12, dy12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
|
||||
@@ -232,7 +213,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint h = NEXT_INT(b);
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_RECT(%d, %d, %d, %d)", x, y, w, h);
|
||||
VKRenderer_RenderRect(&context, VK_TRUE, x, y, w, h);
|
||||
VKRenderer_RenderRect(VK_TRUE, x, y, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
|
||||
@@ -240,7 +221,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint count = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_SPANS");
|
||||
VKRenderer_FillSpans(&context, count, (jint *)b);
|
||||
VKRenderer_FillSpans(count, (jint *) b);
|
||||
SKIP_BYTES(b, count * BYTES_PER_SPAN);
|
||||
}
|
||||
break;
|
||||
@@ -255,7 +236,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn6(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FILL_PARALLELOGRAM(%f, %f, %f, %f, %f, %f)",
|
||||
x11, y11, dx21, dy21, dx12, dy12);
|
||||
VKRenderer_RenderParallelogram(&context, VK_TRUE, x11, y11, dx21, dy21, dx12, dy12);
|
||||
VKRenderer_RenderParallelogram(VK_TRUE, x11, y11, dx21, dy21,
|
||||
dx12, dy12);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
|
||||
@@ -270,7 +252,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
"VKRenderQueue_flushBuffer: FILL_AAPARALLELOGRAM(%f, %f, %f, %f, %f, %f)",
|
||||
x11, y11, dx21, dy21, dx12, dy12);
|
||||
// TODO this is not AA!
|
||||
VKRenderer_RenderParallelogram(&context, VK_TRUE, x11, y11, dx21, dy21, dx12, dy12);
|
||||
VKRenderer_RenderParallelogram(VK_TRUE, x11, y11, dx21, dy21,
|
||||
dx12, dy12);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -317,7 +300,11 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
}
|
||||
if (ginfo->format != sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE) continue;
|
||||
if (ginfo->height*ginfo->rowBytes == 0) continue;
|
||||
VKRenderer_MaskFill(&context, (int) glyphx, (int) glyphy, ginfo->width, ginfo->height, 0, ginfo->rowBytes, ginfo->height*ginfo->rowBytes, ginfo->image);
|
||||
VKRenderer_MaskFill((int) glyphx, (int) glyphy,
|
||||
ginfo->width, ginfo->height,
|
||||
0, ginfo->rowBytes,
|
||||
ginfo->height * ginfo->rowBytes,
|
||||
ginfo->image);
|
||||
}
|
||||
SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
|
||||
}
|
||||
@@ -348,38 +335,33 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jdouble dy1 = NEXT_DOUBLE(b);
|
||||
jdouble dx2 = NEXT_DOUBLE(b);
|
||||
jdouble dy2 = NEXT_DOUBLE(b);
|
||||
jlong pSrc = NEXT_LONG(b);
|
||||
jlong pDst = NEXT_LONG(b);
|
||||
SurfaceDataOps* src = NEXT_SURFACE(b);
|
||||
VKSDOps* dst = NEXT_VK_SURFACE(b);
|
||||
jint hint = EXTRACT_BYTE(packedParams, OFFSET_HINT);
|
||||
jboolean texture = EXTRACT_BOOLEAN(packedParams,
|
||||
OFFSET_TEXTURE);
|
||||
jboolean rtt = EXTRACT_BOOLEAN(packedParams,
|
||||
OFFSET_RTT);
|
||||
jboolean xform = EXTRACT_BOOLEAN(packedParams,
|
||||
OFFSET_XFORM);
|
||||
jboolean isoblit = EXTRACT_BOOLEAN(packedParams,
|
||||
OFFSET_ISOBLIT);
|
||||
VKSDOps *dstOps = (VKSDOps *)jlong_to_ptr(pDst);
|
||||
VKSDOps *oldSurface = context.surface;
|
||||
context.surface = dstOps;
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
VKSDOps* oldSurface = context->surface;
|
||||
context->surface = dst;
|
||||
if (isoblit) {
|
||||
VKBlitLoops_IsoBlit(env, &context, pSrc,
|
||||
xform, hint, texture,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
VKBlitLoops_IsoBlit((VKSDOps*) src,
|
||||
hint,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
} else {
|
||||
jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE);
|
||||
VKBlitLoops_Blit(env, &context, pSrc,
|
||||
xform, hint, srctype, texture,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
jshort srctype = EXTRACT_SHORT(packedParams, OFFSET_SRCTYPE);
|
||||
VKBlitLoops_Blit(env, ptr_to_jlong(src),
|
||||
xform, hint, srctype,
|
||||
sx1, sy1, sx2, sy2,
|
||||
dx1, dy1, dx2, dy2);
|
||||
}
|
||||
context.surface = oldSurface;
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT %p -> %p ", pSrc, pDst)
|
||||
context->surface = oldSurface;
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT %p -> %p ", src, dst)
|
||||
J2dRlsTraceLn8(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT (%d %d %d %d) -> (%f %f %f %f) ",
|
||||
sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT texture=%d rtt=%d xform=%d isoblit=%d",
|
||||
texture, rtt, xform, isoblit)
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: BLIT xform=%d isoblit=%d", xform, isoblit)
|
||||
|
||||
}
|
||||
break;
|
||||
@@ -395,7 +377,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pSrc = NEXT_LONG(b);
|
||||
jlong pDst = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SURFACE_TO_SW_BLIT");
|
||||
VKBlitLoops_SurfaceToSwBlit(env, &context, pSrc, pDst, dsttype, sx, sy, dx, dy, w, h);
|
||||
VKBlitLoops_SurfaceToSwBlit(env, pSrc, pDst, dsttype, sx, sy,
|
||||
dx, dy, w, h);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
|
||||
@@ -411,7 +394,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn7(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: MASK_FILL(%d, %d, %dx%d, maskoff=%d, maskscan=%d, masklen=%d)",
|
||||
x, y, w, h, maskoff, maskscan, masklen);
|
||||
VKRenderer_MaskFill(&context, x, y, w, h, maskoff, maskscan, masklen, pMask);
|
||||
VKRenderer_MaskFill(x, y, w, h,
|
||||
maskoff, maskscan, masklen, pMask);
|
||||
SKIP_BYTES(b, masklen);
|
||||
}
|
||||
break;
|
||||
@@ -437,18 +421,18 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
J2dRlsTraceLn4(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_RECT_CLIP(%d, %d, %d, %d)",
|
||||
x1, y1, x2, y2);
|
||||
ARRAY_RESIZE(context.clipSpanVertices, 0);
|
||||
ARRAY_RESIZE(VKRenderer_GetContext()->clipSpanVertices, 0);
|
||||
jint width = x2 - x1, height = y2 - y1;
|
||||
context.clipRect = (VkRect2D) {{x1, y1}, {CARR_MAX(width, 0), CARR_MAX(height, 0)}};
|
||||
context.clipModCount++;
|
||||
VKRenderer_GetContext()->clipRect = (VkRect2D) {{x1, y1}, {CARR_MAX(width, 0), CARR_MAX(height, 0)}};
|
||||
VKRenderer_GetContext()->clipModCount++;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: BEGIN_SHAPE_CLIP");
|
||||
ARRAY_RESIZE(context.clipSpanVertices, 0);
|
||||
context.clipModCount++;
|
||||
ARRAY_RESIZE(VKRenderer_GetContext()->clipSpanVertices, 0);
|
||||
VKRenderer_GetContext()->clipModCount++;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
|
||||
@@ -456,38 +440,38 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint count = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SHAPE_CLIP_SPANS");
|
||||
size_t offset = ARRAY_SIZE(context.clipSpanVertices);
|
||||
ARRAY_RESIZE(context.clipSpanVertices, offset + count * 6);
|
||||
size_t offset = ARRAY_SIZE(VKRenderer_GetContext()->clipSpanVertices);
|
||||
ARRAY_RESIZE(VKRenderer_GetContext()->clipSpanVertices, offset + count * 6);
|
||||
for (jint i = 0; i < count; i++) {
|
||||
jint x1 = NEXT_INT(b);
|
||||
jint y1 = NEXT_INT(b);
|
||||
jint x2 = NEXT_INT(b);
|
||||
jint y2 = NEXT_INT(b);
|
||||
context.clipSpanVertices[offset + i * 6 + 0] = (VKIntVertex) {x1, y1};
|
||||
context.clipSpanVertices[offset + i * 6 + 1] = (VKIntVertex) {x2, y1};
|
||||
context.clipSpanVertices[offset + i * 6 + 2] = (VKIntVertex) {x2, y2};
|
||||
context.clipSpanVertices[offset + i * 6 + 3] = (VKIntVertex) {x2, y2};
|
||||
context.clipSpanVertices[offset + i * 6 + 4] = (VKIntVertex) {x1, y2};
|
||||
context.clipSpanVertices[offset + i * 6 + 5] = (VKIntVertex) {x1, y1};
|
||||
VKRenderer_GetContext()->clipSpanVertices[offset + i * 6 + 0] = (VKIntVertex) {x1, y1};
|
||||
VKRenderer_GetContext()->clipSpanVertices[offset + i * 6 + 1] = (VKIntVertex) {x2, y1};
|
||||
VKRenderer_GetContext()->clipSpanVertices[offset + i * 6 + 2] = (VKIntVertex) {x2, y2};
|
||||
VKRenderer_GetContext()->clipSpanVertices[offset + i * 6 + 3] = (VKIntVertex) {x2, y2};
|
||||
VKRenderer_GetContext()->clipSpanVertices[offset + i * 6 + 4] = (VKIntVertex) {x1, y2};
|
||||
VKRenderer_GetContext()->clipSpanVertices[offset + i * 6 + 5] = (VKIntVertex) {x1, y1};
|
||||
}
|
||||
context.clipModCount++;
|
||||
VKRenderer_GetContext()->clipModCount++;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: END_SHAPE_CLIP");
|
||||
context.clipRect = NO_CLIP;
|
||||
context.clipModCount++;
|
||||
VKRenderer_GetContext()->clipRect = NO_CLIP;
|
||||
VKRenderer_GetContext()->clipModCount++;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_CLIP");
|
||||
ARRAY_RESIZE(context.clipSpanVertices, 0);
|
||||
context.clipRect = NO_CLIP;
|
||||
context.clipModCount++;
|
||||
ARRAY_RESIZE(VKRenderer_GetContext()->clipSpanVertices, 0);
|
||||
VKRenderer_GetContext()->clipRect = NO_CLIP;
|
||||
VKRenderer_GetContext()->clipModCount++;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
|
||||
@@ -497,9 +481,9 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint flags = NEXT_INT(b);
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_ALPHA_COMPOSITE(%d, %f, %d)", rule, extraAlpha, flags);
|
||||
context.color = color;
|
||||
context.composite = (VKCompositeMode) rule;
|
||||
context.extraAlpha = extraAlpha;
|
||||
VKRenderer_GetContext()->renderColor = VKRenderer_GetContext()->color;
|
||||
VKRenderer_GetContext()->composite = (VKCompositeMode) rule;
|
||||
VKRenderer_GetContext()->extraAlpha = extraAlpha;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
|
||||
@@ -507,19 +491,20 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jint xorPixel = NEXT_INT(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_XOR_COMPOSITE");
|
||||
context.color = VKUtil_DecodeJavaColor(xorPixel);
|
||||
context.color.a = 0.0f; // Alpha is left unchanged in XOR mode.
|
||||
context.composite = LOGIC_COMPOSITE_XOR;
|
||||
context.extraAlpha = 1.0f;
|
||||
VKRenderer_GetContext()->renderColor = VKUtil_DecodeJavaColor(xorPixel, ALPHA_TYPE_STRAIGHT);
|
||||
// TODO Fix XOR mode!
|
||||
// VKRenderer_GetContext()->renderColor.a = 0.0f; // Alpha is left unchanged in XOR mode.
|
||||
VKRenderer_GetContext()->composite = LOGIC_COMPOSITE_XOR;
|
||||
VKRenderer_GetContext()->extraAlpha = 1.0f;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_COMPOSITE");
|
||||
context.color = color;
|
||||
context.composite = ALPHA_COMPOSITE_SRC;
|
||||
context.extraAlpha = 1.0f;
|
||||
VKRenderer_GetContext()->renderColor = VKRenderer_GetContext()->color;
|
||||
VKRenderer_GetContext()->composite = ALPHA_COMPOSITE_SRC;
|
||||
VKRenderer_GetContext()->extraAlpha = 1.0f;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
|
||||
@@ -536,37 +521,39 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
" | %.2f %.2f %.2f |", m10, m11, m12);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
" | 0.00 0.00 1.00 |");
|
||||
context.transform.m00 = m00;
|
||||
context.transform.m10 = m10;
|
||||
context.transform.m01 = m01;
|
||||
context.transform.m11 = m11;
|
||||
context.transform.m02 = m02;
|
||||
context.transform.m12 = m12;
|
||||
VKTransform transform = {
|
||||
.m00 = m00, .m10 = m10, .m01 = m01,
|
||||
.m11 = m11, .m02 = m02, .m12 = m12
|
||||
};
|
||||
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
if (VK_IS_NEQ_TRANSFORM(&context->transform, &transform)) {
|
||||
context->transform = transform;
|
||||
context->transformModCount++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: RESET_TRANSFORM");
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
if (VK_IS_NEQ_TRANSFORM(&context->transform, &VK_ID_TRANSFORM)) {
|
||||
context->transform = VK_ID_TRANSFORM;
|
||||
context->transformModCount++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// context-related ops
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
|
||||
{
|
||||
VKSDOps* src = NEXT_SURFACE(b);
|
||||
VKSDOps* dst = NEXT_SURFACE(b);
|
||||
VKSDOps* src = NEXT_VK_SURFACE(b);
|
||||
VKSDOps* dst = NEXT_VK_SURFACE(b);
|
||||
J2dRlsTraceLn2(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SURFACES src=%p dst=%p", src, dst);
|
||||
|
||||
if (context.surface != NULL && context.surface != dst) {
|
||||
// TODO Problematic surface flush on a context switch without explicit presentation request.
|
||||
// Its presence here should not make any difference, but for some reason does.
|
||||
// Related scenarios need an investigation, e.g. J2Demo.
|
||||
VKRenderer_FlushSurface(context.surface);
|
||||
}
|
||||
|
||||
context.surface = dst;
|
||||
VKRenderer_GetContext()->surface = dst;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
|
||||
@@ -574,12 +561,12 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: SET_SCRATCH_SURFACE");
|
||||
context.surface = NULL;
|
||||
VKRenderer_GetContext()->surface = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
|
||||
{
|
||||
VKSDOps* surface = NEXT_SURFACE(b);
|
||||
VKSDOps* surface = NEXT_VK_SURFACE(b);
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FLUSH_SURFACE (%p)", surface)
|
||||
}
|
||||
@@ -596,14 +583,14 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
jlong pConfigInfo = NEXT_LONG(b);
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: DISPOSE_CONFIG")
|
||||
context.surface = NULL;
|
||||
VKRenderer_GetContext()->surface = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
|
||||
{
|
||||
J2dRlsTraceLn(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: INVALIDATE_CONTEXT");
|
||||
context.surface = NULL;
|
||||
VKRenderer_GetContext()->surface = NULL;
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SYNC:
|
||||
@@ -615,12 +602,13 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_CONFIGURE_SURFACE:
|
||||
{
|
||||
VKSDOps* surface = NEXT_SURFACE(b);
|
||||
VKSDOps* surface = NEXT_VK_SURFACE(b);
|
||||
VKDevice* device = jlong_to_ptr(NEXT_LONG(b));
|
||||
jint width = NEXT_INT(b);
|
||||
jint height = NEXT_INT(b);
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: CONFIGURE_SURFACE (%p) %dx%d", surface, width, height);
|
||||
VKRenderer_ConfigureSurface(surface, (VkExtent2D) {width, height});
|
||||
VKRenderer_ConfigureSurface(surface, (VkExtent2D) {width, height}, device);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -635,7 +623,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
|
||||
case sun_java2d_pipe_BufferedOpCodes_FLUSH_BUFFER:
|
||||
{
|
||||
VKSDOps* surface = NEXT_SURFACE(b);
|
||||
VKSDOps* surface = NEXT_VK_SURFACE(b);
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE,
|
||||
"VKRenderQueue_flushBuffer: FLUSH_BUFFER (%p)", surface)
|
||||
|
||||
@@ -661,11 +649,17 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
|
||||
{
|
||||
jint javaColor = NEXT_INT(b);
|
||||
color = VKUtil_DecodeJavaColor(javaColor);
|
||||
if (COMPOSITE_GROUP(context.composite) == ALPHA_COMPOSITE_GROUP) context.color = color;
|
||||
VKRenderer_GetContext()->color = VKUtil_DecodeJavaColor(javaColor, ALPHA_TYPE_STRAIGHT);
|
||||
if (COMPOSITE_GROUP(VKRenderer_GetContext()->composite) == ALPHA_COMPOSITE_GROUP) {
|
||||
VKRenderer_GetContext()->renderColor = VKRenderer_GetContext()->color;
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKRenderQueue_flushBuffer: SET_COLOR(0x%08x)", javaColor);
|
||||
J2dTraceLn4(J2D_TRACE_VERBOSE, // Print color values with straight alpha for convenience.
|
||||
" srgb={%.3f, %.3f, %.3f, %.3f}", color.r/color.a, color.g/color.a, color.b/color.a, color.a);
|
||||
" srgb={%.3f, %.3f, %.3f, %.3f}",
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).r,
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).g,
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).b,
|
||||
VKUtil_GetRGBA(VKRenderer_GetContext()->color, ALPHA_TYPE_STRAIGHT).a);
|
||||
}
|
||||
break;
|
||||
case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
|
||||
@@ -799,10 +793,8 @@ JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKRenderQueue_flushBuffer
|
||||
}
|
||||
|
||||
// Flush all pending GPU work
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(ge->devices); i++) {
|
||||
VKRenderer_Flush(ge->devices[i].renderer);
|
||||
VKEnv* vk = VKEnv_GetInstance();
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(vk->devices); i++) {
|
||||
VKRenderer_Flush(vk->devices[i].renderer);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
|
||||
@@ -24,14 +24,13 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "sun_java2d_vulkan_VKGPU.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKAllocator.h"
|
||||
#include "VKBuffer.h"
|
||||
#include "VKDevice.h"
|
||||
#include "VKImage.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKSurfaceData.h"
|
||||
@@ -54,6 +53,12 @@ RING_BUFFER(struct PoolEntry_ ## NAME { \
|
||||
(VAR) = RING_BUFFER_FRONT((RENDERER)->NAME)->value; RING_BUFFER_POP_FRONT((RENDERER)->NAME); \
|
||||
}} while(0)
|
||||
|
||||
/**
|
||||
* Check if there are available items in the pool.
|
||||
*/
|
||||
#define POOL_NOT_EMPTY(RENDERER, NAME) \
|
||||
(VKRenderer_CheckPoolEntryAvailable((RENDERER), RING_BUFFER_FRONT((RENDERER)->NAME)))
|
||||
|
||||
/**
|
||||
* Return an item to the pool. It will only become available again
|
||||
* after the next submitted batch of work completes execution on GPU.
|
||||
@@ -84,6 +89,11 @@ RING_BUFFER(struct PoolEntry_ ## NAME { \
|
||||
*/
|
||||
#define POOL_FREE(RENDERER, NAME) RING_BUFFER_FREE((RENDERER)->NAME)
|
||||
|
||||
typedef struct {
|
||||
VKCleanupHandler handler;
|
||||
void* data;
|
||||
} VKCleanupEntry;
|
||||
|
||||
/**
|
||||
* Renderer attached to device.
|
||||
*/
|
||||
@@ -97,11 +107,13 @@ struct VKRenderer {
|
||||
POOL(VKBuffer, vertexBufferPool);
|
||||
POOL(VKTexelBuffer, maskFillBufferPool);
|
||||
POOL(VkFramebuffer, framebufferDestructionQueue);
|
||||
POOL(VKCleanupEntry, cleanupQueue);
|
||||
ARRAY(VKMemory) bufferMemoryPages;
|
||||
ARRAY(VkDescriptorPool) descriptorPools;
|
||||
ARRAY(VkDescriptorPool) imageDescriptorPools;
|
||||
|
||||
/**
|
||||
* Last known timestamp hit by GPU execution. Resources with equal or less timestamp may be safely reused.
|
||||
* Last known timestamp reached by GPU execution. Resources with equal or less timestamp may be safely reused.
|
||||
*/
|
||||
uint64_t readTimestamp;
|
||||
/**
|
||||
@@ -133,6 +145,11 @@ typedef struct {
|
||||
VkBool32 bound;
|
||||
} BufferWritingState;
|
||||
|
||||
typedef struct {
|
||||
BufferWritingState state;
|
||||
uint32_t elements;
|
||||
} BufferWriting;
|
||||
|
||||
/**
|
||||
* Rendering-related info attached to surface.
|
||||
*/
|
||||
@@ -140,6 +157,7 @@ struct VKRenderPass {
|
||||
VKRenderPassContext* context;
|
||||
ARRAY(VKBuffer) vertexBuffers;
|
||||
ARRAY(VKTexelBuffer) maskFillBuffers;
|
||||
ARRAY(VKSDOps*) usedSurfaces;
|
||||
VkRenderPass renderPass; // Non-owning.
|
||||
VkFramebuffer framebuffer;
|
||||
VkCommandBuffer commandBuffer;
|
||||
@@ -150,13 +168,36 @@ struct VKRenderPass {
|
||||
BufferWritingState maskFillBufferWriting;
|
||||
|
||||
VKPipelineDescriptor state;
|
||||
uint64_t transformModCount; // Just a tag to detect when transform was changed.
|
||||
uint64_t clipModCount; // Just a tag to detect when clip was changed.
|
||||
VkBool32 pendingFlush;
|
||||
VkBool32 pendingCommands;
|
||||
VkBool32 pendingClear;
|
||||
uint64_t lastTimestamp; // When was this surface last used?
|
||||
VkBool32 pendingFlush : 1;
|
||||
VkBool32 pendingCommands : 1;
|
||||
VkBool32 pendingClear : 1;
|
||||
AlphaType outAlphaType : 1;
|
||||
};
|
||||
|
||||
// Rendering context is only accessed from VKRenderQueue_flushBuffer,
|
||||
// which is only called from queue flusher thread, no need for synchronization.
|
||||
static VKRenderingContext context = {
|
||||
.surface = NULL,
|
||||
.transform = VK_ID_TRANSFORM,
|
||||
.transformModCount = 1,
|
||||
.color = {},
|
||||
.renderColor = {},
|
||||
.composite = ALPHA_COMPOSITE_SRC_OVER,
|
||||
.extraAlpha = 1.0f,
|
||||
.clipModCount = 1,
|
||||
.clipRect = NO_CLIP,
|
||||
.clipSpanVertices = NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* Accessor to the global rendering context.
|
||||
*/
|
||||
VKRenderingContext *VKRenderer_GetContext() {
|
||||
return &context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for POOL_TAKE macro.
|
||||
*/
|
||||
@@ -231,6 +272,48 @@ static VKTexelBuffer VKRenderer_GetMaskFillBuffer(VKRenderer* renderer) {
|
||||
return texelBuffers[0];
|
||||
}
|
||||
|
||||
#define IMAGE_DESCRIPTOR_POOL_SIZE 64
|
||||
static VkDescriptorSet VKRenderer_AllocateImageDescriptorSet(VKRenderer* renderer, VkDescriptorPool descriptorPool) {
|
||||
VKDevice* device = renderer->device;
|
||||
VkDescriptorSetAllocateInfo allocateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = descriptorPool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &renderer->pipelineContext->textureDescriptorSetLayout
|
||||
};
|
||||
VkDescriptorSet set;
|
||||
VkResult result = device->vkAllocateDescriptorSets(device->handle, &allocateInfo, &set);
|
||||
if (result == VK_SUCCESS) return set;
|
||||
if (result != VK_ERROR_OUT_OF_POOL_MEMORY && result != VK_ERROR_FRAGMENTED_POOL) {
|
||||
VK_IF_ERROR(result) VK_UNHANDLED_ERROR();
|
||||
}
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
void VKRenderer_CreateImageDescriptorSet(VKRenderer* renderer, VkDescriptorPool* descriptorPool, VkDescriptorSet* set) {
|
||||
VKDevice* device = renderer->device;
|
||||
for (int i = ARRAY_SIZE(renderer->imageDescriptorPools) - 1; i >= 0; i--) {
|
||||
*set = VKRenderer_AllocateImageDescriptorSet(renderer, renderer->imageDescriptorPools[i]);
|
||||
if (*set != VK_NULL_HANDLE) {
|
||||
*descriptorPool = renderer->imageDescriptorPools[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
VkDescriptorPoolSize poolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
.descriptorCount = IMAGE_DESCRIPTOR_POOL_SIZE
|
||||
};
|
||||
VkDescriptorPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &poolSize,
|
||||
.maxSets = IMAGE_DESCRIPTOR_POOL_SIZE
|
||||
};
|
||||
VK_IF_ERROR(device->vkCreateDescriptorPool(device->handle, &poolInfo, NULL, descriptorPool)) VK_UNHANDLED_ERROR();
|
||||
ARRAY_PUSH_BACK(renderer->imageDescriptorPools) = *descriptorPool;
|
||||
*set = VKRenderer_AllocateImageDescriptorSet(renderer, *descriptorPool);
|
||||
}
|
||||
|
||||
static VkSemaphore VKRenderer_AddPendingSemaphore(VKRenderer* renderer) {
|
||||
VKDevice* device = renderer->device;
|
||||
VkSemaphore semaphore = VK_NULL_HANDLE;
|
||||
@@ -352,6 +435,10 @@ void VKRenderer_Destroy(VKRenderer* renderer) {
|
||||
device->vkDestroyDescriptorPool(device->handle, renderer->descriptorPools[i], NULL);
|
||||
}
|
||||
ARRAY_FREE(renderer->descriptorPools);
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(renderer->imageDescriptorPools); i++) {
|
||||
device->vkDestroyDescriptorPool(device->handle, renderer->imageDescriptorPools[i], NULL);
|
||||
}
|
||||
ARRAY_FREE(renderer->imageDescriptorPools);
|
||||
|
||||
device->vkDestroySemaphore(device->handle, renderer->timelineSemaphore, NULL);
|
||||
device->vkDestroyCommandPool(device->handle, renderer->commandPool, NULL);
|
||||
@@ -366,6 +453,13 @@ void VKRenderer_Destroy(VKRenderer* renderer) {
|
||||
|
||||
static void VKRenderer_CleanupPendingResources(VKRenderer* renderer) {
|
||||
VKDevice* device = renderer->device;
|
||||
|
||||
while (POOL_NOT_EMPTY(renderer, cleanupQueue)) {
|
||||
VKCleanupEntry entry = {};
|
||||
POOL_TAKE(renderer, cleanupQueue, entry);
|
||||
entry.handler(device, entry.data);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
POOL_TAKE(renderer, framebufferDestructionQueue, framebuffer);
|
||||
@@ -485,7 +579,7 @@ void VKRenderer_Flush(VKRenderer* renderer) {
|
||||
* Prepare image barrier info to be executed in batch, if needed.
|
||||
*/
|
||||
void VKRenderer_AddImageBarrier(VkImageMemoryBarrier* barriers, VKBarrierBatch* batch,
|
||||
VKImage* image, VkPipelineStageFlags stage, VkAccessFlags access, VkImageLayout layout) {
|
||||
VKImage* image, VkPipelineStageFlags stage, VkAccessFlags access, VkImageLayout layout) {
|
||||
assert(barriers != NULL && batch != NULL && image != NULL);
|
||||
// TODO Even if stage, access and layout didn't change, we may still need a barrier against WaW hazard.
|
||||
if (stage != image->lastStage || access != image->lastAccess || layout != image->layout) {
|
||||
@@ -498,7 +592,7 @@ void VKRenderer_AddImageBarrier(VkImageMemoryBarrier* barriers, VKBarrierBatch*
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image->handle,
|
||||
.subresourceRange = { VKImage_GetAspect(image), 0, 1, 0, 1 }
|
||||
.subresourceRange = { VKUtil_GetFormatGroup(image->format).aspect, 0, 1, 0, 1 }
|
||||
};
|
||||
batch->barrierCount++;
|
||||
batch->srcStages |= image->lastStage;
|
||||
@@ -509,6 +603,40 @@ void VKRenderer_AddImageBarrier(VkImageMemoryBarrier* barriers, VKBarrierBatch*
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare buffer barrier info to be executed in batch, if needed.
|
||||
*/
|
||||
void VKRenderer_AddBufferBarrier(VkBufferMemoryBarrier* barriers, VKBarrierBatch* batch,
|
||||
VKBuffer* buffer, VkPipelineStageFlags stage,
|
||||
VkAccessFlags access)
|
||||
{
|
||||
assert(barriers != NULL && batch != NULL && buffer != NULL);
|
||||
if (stage != buffer->lastStage || access != buffer->lastAccess) {
|
||||
barriers[batch->barrierCount] = (VkBufferMemoryBarrier) {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.srcAccessMask = buffer->lastAccess,
|
||||
.dstAccessMask = access,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.buffer = buffer->handle,
|
||||
.offset = 0,
|
||||
.size = VK_WHOLE_SIZE
|
||||
};
|
||||
batch->barrierCount++;
|
||||
batch->srcStages |= buffer->lastStage;
|
||||
batch->dstStages |= stage;
|
||||
buffer->lastStage = stage;
|
||||
buffer->lastAccess = access;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Color RGBA components in a suitable for the current render pass.
|
||||
*/
|
||||
inline RGBA VKRenderer_GetRGBA(VKSDOps* surface, Color color) {
|
||||
return VKUtil_GetRGBA(color, surface->renderPass->outAlphaType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record draw command, if there are any pending vertices in the vertex buffer
|
||||
*/
|
||||
@@ -529,6 +657,7 @@ static void VKRenderer_ResetDrawing(VKSDOps* surface) {
|
||||
assert(surface != NULL && surface->renderPass != NULL);
|
||||
surface->renderPass->state.composite = NO_COMPOSITE;
|
||||
surface->renderPass->state.shader = NO_SHADER;
|
||||
surface->renderPass->transformModCount = 0;
|
||||
surface->renderPass->firstVertex = 0;
|
||||
surface->renderPass->vertexCount = 0;
|
||||
surface->renderPass->vertexBufferWriting = (BufferWritingState) {NULL, 0, VK_FALSE};
|
||||
@@ -564,14 +693,21 @@ static void VKRenderer_DiscardRenderPass(VKSDOps* surface) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKRenderer_DiscardRenderPass(%p)", surface);
|
||||
}
|
||||
}
|
||||
static void VKRenderer_FlushDependentRenderPasses(VKSDOps* surface);
|
||||
|
||||
void VKRenderer_DestroyRenderPass(VKSDOps* surface) {
|
||||
assert(surface != NULL);
|
||||
if (surface->renderPass == NULL) return;
|
||||
VKDevice* device = surface->device;
|
||||
// Wait while surface & related resources are being used by the device.
|
||||
if (device != NULL) {
|
||||
VKRenderer_FlushDependentRenderPasses(surface);
|
||||
if (surface->lastTimestamp == device->renderer->writeTimestamp) {
|
||||
VKRenderer_Flush(device->renderer);
|
||||
}
|
||||
VKRenderer_Wait(device->renderer, surface->lastTimestamp);
|
||||
}
|
||||
if (surface->renderPass == NULL) return;
|
||||
if (device != NULL && device->renderer != NULL) {
|
||||
// Wait while surface resources are being used by the device.
|
||||
VKRenderer_Wait(device->renderer, surface->renderPass->lastTimestamp);
|
||||
VKRenderer_CleanupPendingResources(device->renderer);
|
||||
VKRenderer_DiscardRenderPass(surface);
|
||||
// Release resources.
|
||||
@@ -607,14 +743,16 @@ static VkBool32 VKRenderer_InitRenderPass(VKSDOps* surface) {
|
||||
(*renderPass) = (VKRenderPass) {
|
||||
.state = {
|
||||
.stencilMode = STENCIL_MODE_NONE,
|
||||
.dstOpaque = VKSD_IsOpaque(surface),
|
||||
.inAlphaType = ALPHA_TYPE_UNKNOWN,
|
||||
.composite = NO_COMPOSITE,
|
||||
.shader = NO_SHADER
|
||||
},
|
||||
.transformModCount = 0,
|
||||
.clipModCount = 0,
|
||||
.pendingFlush = VK_FALSE,
|
||||
.pendingCommands = VK_FALSE,
|
||||
.pendingClear = VK_TRUE, // Clear the surface by default
|
||||
.lastTimestamp = 0
|
||||
};
|
||||
|
||||
// Initialize pipelines. They are cached until surface format changes.
|
||||
@@ -645,7 +783,7 @@ static void VKRenderer_InitFramebuffer(VKSDOps* surface) {
|
||||
// Initialize framebuffer.
|
||||
if (renderPass->framebuffer == VK_NULL_HANDLE) {
|
||||
renderPass->renderPass = renderPass->context->renderPass[surface->stencil != NULL];
|
||||
VkImageView views[] = { surface->image->view, VK_NULL_HANDLE };
|
||||
VkImageView views[] = { VKImage_GetView(device, surface->image, surface->image->format, 0), VK_NULL_HANDLE };
|
||||
VkFramebufferCreateInfo framebufferCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = renderPass->renderPass,
|
||||
@@ -657,7 +795,7 @@ static void VKRenderer_InitFramebuffer(VKSDOps* surface) {
|
||||
};
|
||||
if (surface->stencil != NULL) {
|
||||
framebufferCreateInfo.attachmentCount = 2;
|
||||
views[1] = surface->stencil->view;
|
||||
views[1] = VKImage_GetView(device, surface->stencil, surface->stencil->format, 0);
|
||||
}
|
||||
VK_IF_ERROR(device->vkCreateFramebuffer(device->handle, &framebufferCreateInfo, NULL,
|
||||
&renderPass->framebuffer)) VK_UNHANDLED_ERROR();
|
||||
@@ -671,6 +809,7 @@ static void VKRenderer_InitFramebuffer(VKSDOps* surface) {
|
||||
*/
|
||||
static void VKRenderer_BeginRenderPass(VKSDOps* surface) {
|
||||
assert(surface != NULL && surface->renderPass != NULL && !surface->renderPass->pendingCommands);
|
||||
VKRenderer_FlushDependentRenderPasses(surface);
|
||||
VKRenderer_InitFramebuffer(surface);
|
||||
// We may have a pending flush, which is already obsolete.
|
||||
surface->renderPass->pendingFlush = VK_FALSE;
|
||||
@@ -716,8 +855,9 @@ static void VKRenderer_BeginRenderPass(VKSDOps* surface) {
|
||||
VkClearAttachment clearAttachment = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.colorAttachment = 0,
|
||||
.clearValue = surface->background.vkClearValue
|
||||
.clearValue = VKRenderer_GetRGBA(surface, surface->background).vkClearValue
|
||||
};
|
||||
if (VKSD_IsOpaque(surface)) clearAttachment.clearValue.color.float32[3] = 1.0f;
|
||||
VkClearRect clearRect = {
|
||||
.rect = {{0, 0}, surface->image->extent},
|
||||
.baseArrayLayer = 0,
|
||||
@@ -737,17 +877,6 @@ static void VKRenderer_BeginRenderPass(VKSDOps* surface) {
|
||||
.maxDepth = 1.0f
|
||||
};
|
||||
device->vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
// Calculate inverse viewport for vertex shader.
|
||||
viewport.width = 2.0f / viewport.width;
|
||||
viewport.height = 2.0f / viewport.height;
|
||||
device->vkCmdPushConstants(
|
||||
commandBuffer,
|
||||
renderer->pipelineContext->colorPipelineLayout, // TODO what if our pipeline layout differs?
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0,
|
||||
sizeof(float) * 2,
|
||||
&viewport.width
|
||||
);
|
||||
|
||||
surface->renderPass->pendingCommands = VK_TRUE;
|
||||
J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "VKRenderer_BeginRenderPass(%p)", surface);
|
||||
@@ -757,16 +886,43 @@ static void VKRenderer_BeginRenderPass(VKSDOps* surface) {
|
||||
* End render pass for the surface and record it into the primary command buffer,
|
||||
* which will be executed on the next VKRenderer_Flush.
|
||||
*/
|
||||
void VKRenderer_FlushRenderPass(VKSDOps* surface) {
|
||||
assert(surface != NULL && surface->renderPass != NULL);
|
||||
VkBool32 VKRenderer_FlushRenderPass(VKSDOps* surface) {
|
||||
assert(surface != NULL);
|
||||
// If pendingFlush is TRUE, pendingCommands must be FALSE
|
||||
assert(surface->renderPass == NULL || !surface->renderPass->pendingFlush || !surface->renderPass->pendingCommands);
|
||||
// Note that we skip render pass initialization, if we have pending flush,
|
||||
// which means that we missed the last flush, but didn't start a new render pass yet.
|
||||
// So now we are going to catch up the last frame, and don't need reconfiguration.
|
||||
// We also skip initialization if we have pending commands, because that means we are in the middle of frame.
|
||||
if (surface->renderPass == NULL || (!surface->renderPass->pendingCommands && !surface->renderPass->pendingFlush)) {
|
||||
if (!VKRenderer_InitRenderPass(surface)) return VK_FALSE;
|
||||
// Check for pendingClear after VKRenderer_InitRenderPass, it may be set after reconfiguration.
|
||||
if (!surface->renderPass->pendingClear) return VK_FALSE;
|
||||
}
|
||||
assert(surface->renderPass != NULL);
|
||||
|
||||
VKRenderer_FlushDraw(surface);
|
||||
VkBool32 hasCommands = surface->renderPass->pendingCommands, clear = surface->renderPass->pendingClear;
|
||||
if(!hasCommands && !clear) return;
|
||||
if(!hasCommands && !clear) return VK_FALSE;
|
||||
VKDevice* device = surface->device;
|
||||
VKRenderer* renderer = device->renderer;
|
||||
surface->renderPass->lastTimestamp = renderer->writeTimestamp;
|
||||
VkCommandBuffer cb = VKRenderer_Record(renderer);
|
||||
|
||||
// Update dependencies on used surfaces.
|
||||
surface->lastTimestamp = renderer->writeTimestamp;
|
||||
for (uint32_t i = 0, surfaces = (uint32_t) ARRAY_SIZE(surface->renderPass->usedSurfaces); i < surfaces; i++) {
|
||||
VKSDOps* usedSurface = surface->renderPass->usedSurfaces[i];
|
||||
usedSurface->lastTimestamp = renderer->writeTimestamp;
|
||||
uint32_t newSize = 0, oldSize = (uint32_t) ARRAY_SIZE(usedSurface->dependentSurfaces);
|
||||
for (uint32_t j = 0; j < oldSize; j++) {
|
||||
VKSDOps* s = usedSurface->dependentSurfaces[j];
|
||||
if (s != surface) usedSurface->dependentSurfaces[newSize++] = s;
|
||||
}
|
||||
if (newSize != oldSize) ARRAY_RESIZE(usedSurface->dependentSurfaces, newSize);
|
||||
}
|
||||
ARRAY_RESIZE(surface->renderPass->usedSurfaces, 0);
|
||||
|
||||
|
||||
// Insert barriers to prepare surface for rendering.
|
||||
VkImageMemoryBarrier barriers[2];
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
@@ -810,24 +966,31 @@ void VKRenderer_FlushRenderPass(VKSDOps* surface) {
|
||||
device->vkCmdEndRenderPass(cb);
|
||||
VKRenderer_ResetDrawing(surface);
|
||||
J2dRlsTraceLn3(J2D_TRACE_VERBOSE, "VKRenderer_FlushRenderPass(%p): hasCommands=%d, clear=%d", surface, hasCommands, clear);
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush render passes depending on a given surface.
|
||||
* This function must be called before mutating a surface
|
||||
* because there may be pending render passes reading from that surface.
|
||||
*/
|
||||
static void VKRenderer_FlushDependentRenderPasses(VKSDOps* surface) {
|
||||
// We're going to clear dependentSurfaces in the end anyway,
|
||||
// so temporarily reset it to NULL to save on removing flushed render passes one-by-one.
|
||||
ARRAY(VKSDOps*) deps = surface->dependentSurfaces;
|
||||
surface->dependentSurfaces = NULL;
|
||||
uint32_t size = (uint32_t) ARRAY_SIZE(deps);
|
||||
if (size > 0) J2dRlsTraceLn2(J2D_TRACE_VERBOSE, "VKRenderer_FlushDependentRenderPasses(%p): %d", surface, size);
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
VKRenderer_FlushRenderPass(deps[i]);
|
||||
}
|
||||
ARRAY_RESIZE(deps, 0);
|
||||
surface->dependentSurfaces = deps;
|
||||
}
|
||||
void VKRenderer_FlushSurface(VKSDOps* surface) {
|
||||
assert(surface != NULL);
|
||||
// If pendingFlush is TRUE, pendingCommands must be FALSE
|
||||
assert(surface->renderPass == NULL || !surface->renderPass->pendingFlush || !surface->renderPass->pendingCommands);
|
||||
// Note that we skip render pass initialization, if we have pending flush,
|
||||
// which means that we missed the last flush, but didn't start a new render pass yet.
|
||||
// So now we are going to catch up the last frame, and don't need reconfiguration.
|
||||
// We also skip initialization if we have pending commands, because that means we are in the middle of frame.
|
||||
if (surface->renderPass == NULL || (!surface->renderPass->pendingCommands && !surface->renderPass->pendingFlush)) {
|
||||
if (!VKRenderer_InitRenderPass(surface)) return;
|
||||
// Check for pendingClear after VKRenderer_InitRenderPass, it may be set after reconfiguration.
|
||||
if (!surface->renderPass->pendingClear) return;
|
||||
}
|
||||
|
||||
if (!VKRenderer_FlushRenderPass(surface)) return;
|
||||
surface->renderPass->pendingFlush = VK_FALSE;
|
||||
VKRenderer_FlushRenderPass(surface);
|
||||
|
||||
// If this is a swapchain surface, we need to blit the content onto it and queue it for presentation.
|
||||
if (surface->drawableType == VKSD_WINDOW) {
|
||||
@@ -842,8 +1005,8 @@ void VKRenderer_FlushSurface(VKSDOps* surface) {
|
||||
|
||||
VKDevice* device = surface->device;
|
||||
VKRenderer* renderer = device->renderer;
|
||||
surface->renderPass->lastTimestamp = renderer->writeTimestamp;
|
||||
VkCommandBuffer cb = VKRenderer_Record(renderer);
|
||||
surface->lastTimestamp = renderer->writeTimestamp;
|
||||
|
||||
// Acquire swapchain image.
|
||||
VkSemaphore acquireSemaphore = VKRenderer_AddPendingSemaphore(renderer);
|
||||
@@ -915,9 +1078,10 @@ void VKRenderer_FlushSurface(VKSDOps* surface) {
|
||||
}
|
||||
}
|
||||
|
||||
void VKRenderer_ConfigureSurface(VKSDOps* surface, VkExtent2D extent) {
|
||||
void VKRenderer_ConfigureSurface(VKSDOps* surface, VkExtent2D extent, VKDevice* device) {
|
||||
assert(surface != NULL);
|
||||
surface->requestedExtent = extent;
|
||||
surface->requestedDevice = device;
|
||||
// We must only do pending flush between frames.
|
||||
if (surface->renderPass != NULL && surface->renderPass->pendingFlush) {
|
||||
if (surface->renderPass->pendingCommands) {
|
||||
@@ -933,26 +1097,35 @@ void VKRenderer_ConfigureSurface(VKSDOps* surface, VkExtent2D extent) {
|
||||
|
||||
/**
|
||||
* Allocate bytes for writing into buffer. Returned state contains:
|
||||
* - data - pointer to the beginning of buffer, or NULL, if there is no buffer yet.
|
||||
* - offset - writing offset into the buffer data, or 0, if there is no buffer yet.
|
||||
* - bound - whether corresponding buffer is bound to the command buffer,
|
||||
* caller is responsible for checking this value and setting up & binding the buffer.
|
||||
* - state.data - pointer to the beginning of buffer, or NULL, if there is no buffer yet.
|
||||
* - state.offset - writing offset into the buffer data, or 0, if there is no buffer yet.
|
||||
* - state.bound - whether corresponding buffer is bound to the command buffer,
|
||||
* caller is responsible for checking this value and setting up & binding the buffer.
|
||||
* - elements - number of actually allocated elements.
|
||||
*/
|
||||
inline BufferWritingState VKRenderer_AllocateBufferData(VKSDOps* surface, BufferWritingState* writingState,
|
||||
VkDeviceSize size, VkDeviceSize maxBufferSize) {
|
||||
BufferWriting VKRenderer_AllocateBufferData(VKSDOps* surface, BufferWritingState* writingState,
|
||||
VkDeviceSize elements, VkDeviceSize elementSize,
|
||||
VkDeviceSize maxBufferSize) {
|
||||
assert(surface != NULL && surface->renderPass != NULL && writingState != NULL);
|
||||
assert(size <= maxBufferSize);
|
||||
BufferWritingState result = *writingState;
|
||||
writingState->offset += size;
|
||||
// Overflow, flush drawing commands and take another buffer.
|
||||
if (writingState->offset > maxBufferSize) {
|
||||
VKRenderer_FlushDraw(surface);
|
||||
writingState->offset = size;
|
||||
result.offset = 0;
|
||||
result.bound = VK_FALSE;
|
||||
result.data = NULL;
|
||||
assert(elementSize <= maxBufferSize);
|
||||
VkDeviceSize totalSize = elements * elementSize;
|
||||
BufferWriting result = { *writingState, elements };
|
||||
writingState->offset += totalSize;
|
||||
if (writingState->offset > maxBufferSize) { // Overflow.
|
||||
if (result.state.offset + elementSize > maxBufferSize) {
|
||||
// Cannot fit a single element, flush drawing commands and take another buffer.
|
||||
VKRenderer_FlushDraw(surface);
|
||||
result.state.offset = 0;
|
||||
result.state.bound = VK_FALSE;
|
||||
result.state.data = NULL;
|
||||
}
|
||||
// Calculate the number of remaining elements we can fit.
|
||||
result.elements = (maxBufferSize - result.state.offset) / elementSize;
|
||||
assert(result.elements > 0);
|
||||
if (result.elements > elements) result.elements = elements;
|
||||
writingState->offset = result.state.offset + result.elements * elementSize;
|
||||
}
|
||||
writingState->bound = VK_TRUE; // We assume caller will check the result and bind the buffer right away!
|
||||
writingState->bound = VK_TRUE; // We assume the caller will check the result and bind the buffer right away!
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -964,25 +1137,26 @@ inline BufferWritingState VKRenderer_AllocateBufferData(VKSDOps* surface, Buffer
|
||||
* This function must be called after all dynamic allocation functions,
|
||||
* which can invalidate drawing state, e.g. VKRenderer_AllocateMaskFillBytes.
|
||||
*/
|
||||
static void* VKRenderer_AllocateVertices(const VKRenderingContext* context, uint32_t vertices, size_t vertexSize) {
|
||||
uint32_t VKRenderer_AllocateVertices(uint32_t primitives, uint32_t vertices, size_t vertexSize, void** result) {
|
||||
assert(vertices > 0 && vertexSize > 0);
|
||||
assert(vertexSize * vertices <= VERTEX_BUFFER_SIZE);
|
||||
VKSDOps* surface = context->surface;
|
||||
BufferWritingState state = VKRenderer_AllocateBufferData(
|
||||
surface, &surface->renderPass->vertexBufferWriting, (VkDeviceSize) (vertexSize * vertices), VERTEX_BUFFER_SIZE);
|
||||
if (!state.bound) {
|
||||
if (state.data == NULL) {
|
||||
VKSDOps* surface = VKRenderer_GetContext()->surface;
|
||||
BufferWriting writing = VKRenderer_AllocateBufferData(
|
||||
surface, &surface->renderPass->vertexBufferWriting, primitives, vertices * vertexSize, VERTEX_BUFFER_SIZE);
|
||||
if (!writing.state.bound) {
|
||||
if (writing.state.data == NULL) {
|
||||
VKBuffer buffer = VKRenderer_GetVertexBuffer(surface->device->renderer);
|
||||
ARRAY_PUSH_BACK(surface->renderPass->vertexBuffers) = buffer;
|
||||
surface->renderPass->vertexBufferWriting.data = state.data = buffer.data;
|
||||
surface->renderPass->vertexBufferWriting.data = writing.state.data = buffer.data;
|
||||
}
|
||||
assert(ARRAY_SIZE(surface->renderPass->vertexBuffers) > 0);
|
||||
surface->renderPass->firstVertex = surface->renderPass->vertexCount = 0;
|
||||
surface->device->vkCmdBindVertexBuffers(surface->renderPass->commandBuffer, 0, 1,
|
||||
&(ARRAY_LAST(surface->renderPass->vertexBuffers).handle), &state.offset);
|
||||
&(ARRAY_LAST(surface->renderPass->vertexBuffers).handle), &writing.state.offset);
|
||||
}
|
||||
surface->renderPass->vertexCount += vertices;
|
||||
return (void*) ((uint8_t*) state.data + state.offset);
|
||||
surface->renderPass->vertexCount += writing.elements * vertices;
|
||||
*((uint8_t**) result) = (uint8_t*) writing.state.data + writing.state.offset;
|
||||
return writing.elements;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -992,22 +1166,23 @@ static void* VKRenderer_AllocateVertices(const VKRenderingContext* context, uint
|
||||
* This function must be called after all dynamic allocation functions,
|
||||
* which can invalidate drawing state, e.g. VKRenderer_AllocateMaskFillBytes.
|
||||
*/
|
||||
#define VK_DRAW(VERTICES, CONTEXT, VERTEX_COUNT) \
|
||||
(VERTICES) = VKRenderer_AllocateVertices((CONTEXT), (VERTEX_COUNT), sizeof((VERTICES)[0]))
|
||||
#define VK_DRAW(VERTICES, PRIMITIVE_COUNT, VERTEX_COUNT) \
|
||||
VKRenderer_AllocateVertices((PRIMITIVE_COUNT), (VERTEX_COUNT), sizeof((VERTICES)[0]), (void**) &(VERTICES))
|
||||
|
||||
|
||||
/**
|
||||
* Allocate bytes from mask fill buffer. VKRenderer_Validate must have been called before.
|
||||
* This function cannot take more bytes than fits into single mask fill buffer at once.
|
||||
* Caller must write data at the returned pointer DrawingBufferWritingState.data
|
||||
* and take into account DrawingBufferWritingState.offset from the beginning of the bound buffer.
|
||||
* Caller must write data at the returned pointer VKBufferWritingState.data
|
||||
* and take into account VKBufferWritingState.offset from the beginning of the bound buffer.
|
||||
* This function can invalidate drawing state, always call it before VK_DRAW.
|
||||
*/
|
||||
static BufferWritingState VKRenderer_AllocateMaskFillBytes(const VKRenderingContext* context, uint32_t size) {
|
||||
static BufferWritingState VKRenderer_AllocateMaskFillBytes(uint32_t size) {
|
||||
assert(size > 0);
|
||||
assert(size <= MASK_FILL_BUFFER_SIZE);
|
||||
VKSDOps* surface = context->surface;
|
||||
VKSDOps* surface = VKRenderer_GetContext()->surface;
|
||||
BufferWritingState state = VKRenderer_AllocateBufferData(
|
||||
surface, &surface->renderPass->maskFillBufferWriting, size, MASK_FILL_BUFFER_SIZE);
|
||||
surface, &surface->renderPass->maskFillBufferWriting, 1, size, MASK_FILL_BUFFER_SIZE).state;
|
||||
if (!state.bound) {
|
||||
if (state.data == NULL) {
|
||||
VKTexelBuffer buffer = VKRenderer_GetMaskFillBuffer(surface->device->renderer);
|
||||
@@ -1015,7 +1190,7 @@ static BufferWritingState VKRenderer_AllocateMaskFillBytes(const VKRenderingCont
|
||||
surface->renderPass->maskFillBufferWriting.data = state.data = buffer.buffer.data;
|
||||
}
|
||||
assert(ARRAY_SIZE(surface->renderPass->maskFillBuffers) > 0);
|
||||
surface->device->vkCmdBindDescriptorSets(context->surface->renderPass->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
surface->device->vkCmdBindDescriptorSets(surface->renderPass->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
surface->device->renderer->pipelineContext->maskFillPipelineLayout,
|
||||
0, 1, &ARRAY_LAST(surface->renderPass->maskFillBuffers).descriptorSet, 0, NULL);
|
||||
}
|
||||
@@ -1023,6 +1198,31 @@ static BufferWritingState VKRenderer_AllocateMaskFillBytes(const VKRenderingCont
|
||||
return state;
|
||||
}
|
||||
|
||||
static void VKRenderer_ValidateTransform() {
|
||||
VKRenderingContext* context = VKRenderer_GetContext();
|
||||
assert(context->surface != NULL);
|
||||
VKSDOps* surface = context->surface;
|
||||
VKRenderPass* renderPass = surface->renderPass;
|
||||
if (renderPass->transformModCount != context->transformModCount) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "VKRenderer_ValidateTransform: updating transform");
|
||||
VKRenderer_FlushDraw(surface);
|
||||
renderPass->transformModCount = context->transformModCount;
|
||||
// Calculate user to device transform.
|
||||
VKTransform transform = {
|
||||
2.0f / (float) surface->image->extent.width, 0.0f, -1.0f,
|
||||
0.0f, 2.0f / (float) surface->image->extent.height, -1.0f
|
||||
};
|
||||
// Combine it with user transform.
|
||||
VKUtil_ConcatenateTransform(&transform, &context->transform);
|
||||
// Push the transform into shader.
|
||||
surface->device->vkCmdPushConstants(
|
||||
renderPass->commandBuffer,
|
||||
surface->device->renderer->pipelineContext->colorPipelineLayout, // TODO what if our pipeline layout differs?
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(VKTransform), &transform
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup stencil attachment according to the context clip state.
|
||||
* If there is a clip shape, attachment is cleared with "fail" value and then
|
||||
@@ -1035,6 +1235,7 @@ static void VKRenderer_SetupStencil(const VKRenderingContext* context) {
|
||||
VKRenderPass* renderPass = surface->renderPass;
|
||||
VkCommandBuffer cb = renderPass->commandBuffer;
|
||||
VKRenderer_FlushDraw(surface);
|
||||
VKRenderer_ValidateTransform();
|
||||
|
||||
// Clear stencil attachment.
|
||||
VkClearAttachment clearAttachment = {
|
||||
@@ -1051,12 +1252,14 @@ static void VKRenderer_SetupStencil(const VKRenderingContext* context) {
|
||||
|
||||
// Bind the clip pipeline.
|
||||
surface->device->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
VKPipelines_GetPipeline(surface->renderPass->context, (VKPipelineDescriptor) {
|
||||
VKPipelines_GetPipelineInfo(surface->renderPass->context, (VKPipelineDescriptor) {
|
||||
.stencilMode = STENCIL_MODE_ON,
|
||||
.dstOpaque = VK_TRUE,
|
||||
.inAlphaType = ALPHA_TYPE_UNKNOWN,
|
||||
.composite = NO_COMPOSITE,
|
||||
.shader = SHADER_CLIP,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
|
||||
}));
|
||||
}).pipeline);
|
||||
// Reset vertex buffer binding.
|
||||
renderPass->vertexBufferWriting.bound = VK_FALSE;
|
||||
|
||||
@@ -1067,7 +1270,7 @@ static void VKRenderer_SetupStencil(const VKRenderingContext* context) {
|
||||
uint32_t currentDraw = ARRAY_SIZE(context->clipSpanVertices) - drawn;
|
||||
if (currentDraw > MAX_VERTICES_PER_DRAW) currentDraw = MAX_VERTICES_PER_DRAW;
|
||||
else if (currentDraw == 0) break;
|
||||
VK_DRAW(vs, context, currentDraw);
|
||||
VK_DRAW(vs, 1, currentDraw);
|
||||
memcpy(vs, context->clipSpanVertices + drawn, currentDraw * sizeof(VKIntVertex));
|
||||
drawn += currentDraw;
|
||||
}
|
||||
@@ -1077,12 +1280,31 @@ static void VKRenderer_SetupStencil(const VKRenderingContext* context) {
|
||||
renderPass->state.shader = NO_SHADER;
|
||||
}
|
||||
|
||||
void VKRenderer_DisposeOnCleanup(VKRenderer* renderer, VKCleanupHandler hnd, void* data) {
|
||||
if (renderer == NULL) return;
|
||||
VKCleanupEntry entry = {hnd, data};
|
||||
POOL_RETURN(renderer, cleanupQueue, entry);
|
||||
}
|
||||
|
||||
void VKRenderer_RecordBarriers(VKRenderer* renderer,
|
||||
VkBufferMemoryBarrier* bufferBarriers, VKBarrierBatch* bufferBatch,
|
||||
VkImageMemoryBarrier* imageBarriers, VKBarrierBatch* imageBatch) {
|
||||
assert(renderer != NULL && renderer->device != NULL);
|
||||
if ((bufferBatch == NULL || bufferBatch->barrierCount == 0) &&
|
||||
(imageBatch == NULL || imageBatch->barrierCount == 0)) return;
|
||||
VkPipelineStageFlags srcStages = (bufferBatch != NULL ? bufferBatch->srcStages : 0) | (imageBatch != NULL ? imageBatch->srcStages : 0);
|
||||
VkPipelineStageFlags dstStages = (bufferBatch != NULL ? bufferBatch->dstStages : 0) | (imageBatch != NULL ? imageBatch->dstStages : 0);
|
||||
renderer->device->vkCmdPipelineBarrier(VKRenderer_Record(renderer), srcStages, dstStages,
|
||||
0, 0, NULL,
|
||||
bufferBatch != NULL ? bufferBatch->barrierCount : 0, bufferBarriers,
|
||||
imageBatch != NULL ? imageBatch->barrierCount : 0, imageBarriers);
|
||||
}
|
||||
/**
|
||||
* Setup pipeline for drawing. Returns FALSE if surface is not yet ready for drawing.
|
||||
*/
|
||||
VkBool32 VKRenderer_Validate(const VKRenderingContext* context, VKShader shader, VkPrimitiveTopology topology) {
|
||||
assert(context != NULL && context->surface != NULL);
|
||||
VKSDOps* surface = context->surface;
|
||||
VkBool32 VKRenderer_Validate(VKShader shader, VkPrimitiveTopology topology, AlphaType inAlphaType) {
|
||||
assert(context.surface != NULL);
|
||||
VKSDOps* surface = context.surface;
|
||||
|
||||
// Init render pass.
|
||||
if (surface->renderPass == NULL || !surface->renderPass->pendingCommands) {
|
||||
@@ -1093,53 +1315,66 @@ VkBool32 VKRenderer_Validate(const VKRenderingContext* context, VKShader shader,
|
||||
VKRenderPass* renderPass = surface->renderPass;
|
||||
|
||||
// Validate render pass state.
|
||||
if (renderPass->state.composite != context->composite ||
|
||||
renderPass->clipModCount != context->clipModCount) {
|
||||
if (renderPass->state.composite != context.composite ||
|
||||
renderPass->clipModCount != context.clipModCount) {
|
||||
// ALPHA_COMPOSITE_DST keeps destination intact, so don't even bother to change the state.
|
||||
if (context->composite == ALPHA_COMPOSITE_DST) return VK_FALSE;
|
||||
if (context.composite == ALPHA_COMPOSITE_DST) return VK_FALSE;
|
||||
// Check whether a logic composite is requested / supported.
|
||||
if (COMPOSITE_GROUP(context.composite) == LOGIC_COMPOSITE_GROUP &&
|
||||
(surface->device->caps & sun_java2d_vulkan_VKGPU_CAP_LOGIC_OP_BIT) == 0) {
|
||||
J2dTraceLn(J2D_TRACE_ERROR, "VKRenderer_Validate: logic composite not supported");
|
||||
return VK_FALSE;
|
||||
}
|
||||
VKCompositeMode oldComposite = renderPass->state.composite;
|
||||
VkBool32 clipChanged = renderPass->clipModCount != context->clipModCount;
|
||||
VkBool32 clipChanged = renderPass->clipModCount != context.clipModCount;
|
||||
// Init stencil attachment, if needed.
|
||||
if (clipChanged && ARRAY_SIZE(context->clipSpanVertices) > 0 && surface->stencil == NULL) {
|
||||
if (clipChanged && ARRAY_SIZE(context.clipSpanVertices) > 0 && surface->stencil == NULL) {
|
||||
if (surface->renderPass->pendingCommands) VKRenderer_FlushRenderPass(surface);
|
||||
if (!VKSD_ConfigureImageSurfaceStencil(surface)) return VK_FALSE;
|
||||
}
|
||||
// Update state.
|
||||
VKRenderer_FlushDraw(surface);
|
||||
renderPass->state.composite = context->composite;
|
||||
renderPass->clipModCount = context->clipModCount;
|
||||
renderPass->state.composite = context.composite;
|
||||
renderPass->clipModCount = context.clipModCount;
|
||||
// Begin render pass.
|
||||
VkBool32 renderPassJustStarted = !renderPass->pendingCommands;
|
||||
if (renderPassJustStarted) VKRenderer_BeginRenderPass(surface);
|
||||
// Validate current clip.
|
||||
if (clipChanged || renderPassJustStarted) {
|
||||
J2dTraceLn(J2D_TRACE_VERBOSE, "VKRenderer_Validate: updating clip");
|
||||
surface->device->vkCmdSetScissor(renderPass->commandBuffer, 0, 1, &context->clipRect);
|
||||
surface->device->vkCmdSetScissor(renderPass->commandBuffer, 0, 1, &context.clipRect);
|
||||
if (clipChanged) {
|
||||
if (ARRAY_SIZE(context->clipSpanVertices) > 0) {
|
||||
VKRenderer_SetupStencil(context);
|
||||
if (ARRAY_SIZE(context.clipSpanVertices) > 0) {
|
||||
VKRenderer_SetupStencil(&context);
|
||||
renderPass->state.stencilMode = STENCIL_MODE_ON;
|
||||
} else renderPass->state.stencilMode = surface->stencil != NULL ? STENCIL_MODE_OFF : STENCIL_MODE_NONE;
|
||||
}
|
||||
}
|
||||
// Validate current composite.
|
||||
if (oldComposite != context->composite) {
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "VKRenderer_Validate: updating composite, old=%d, new=%d", oldComposite, context->composite);
|
||||
if (oldComposite != context.composite) {
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "VKRenderer_Validate: updating composite, old=%d, new=%d", oldComposite, context.composite);
|
||||
// Reset the pipeline.
|
||||
renderPass->state.shader = NO_SHADER;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate current transform.
|
||||
VKRenderer_ValidateTransform();
|
||||
|
||||
// Validate current pipeline.
|
||||
if (renderPass->state.shader != shader || renderPass->state.topology != topology) {
|
||||
if (renderPass->state.shader != shader ||
|
||||
renderPass->state.topology != topology ||
|
||||
renderPass->state.inAlphaType != inAlphaType) {
|
||||
J2dTraceLn2(J2D_TRACE_VERBOSE, "VKRenderer_Validate: updating pipeline, old=%d, new=%d",
|
||||
renderPass->state.shader, shader);
|
||||
VKRenderer_FlushDraw(surface);
|
||||
VkCommandBuffer cb = renderPass->commandBuffer;
|
||||
renderPass->state.shader = shader;
|
||||
renderPass->state.topology = topology;
|
||||
surface->device->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
VKPipelines_GetPipeline(renderPass->context, renderPass->state));
|
||||
renderPass->state.inAlphaType = inAlphaType;
|
||||
VKPipelineInfo pipelineInfo = VKPipelines_GetPipelineInfo(renderPass->context, renderPass->state);
|
||||
renderPass->outAlphaType = pipelineInfo.outAlphaType;
|
||||
surface->device->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineInfo.pipeline);
|
||||
renderPass->vertexBufferWriting.bound = VK_FALSE;
|
||||
renderPass->maskFillBufferWriting.bound = VK_FALSE;
|
||||
}
|
||||
@@ -1148,18 +1383,20 @@ VkBool32 VKRenderer_Validate(const VKRenderingContext* context, VKShader shader,
|
||||
|
||||
// Drawing operations.
|
||||
|
||||
void VKRenderer_RenderRect(const VKRenderingContext* context, VkBool32 fill,
|
||||
jint x, jint y, jint w, jint h) {
|
||||
VKRenderer_RenderParallelogram(context, fill, (float) x, (float) y, (float) w, 0, 0, (float) h);
|
||||
void VKRenderer_RenderRect(VkBool32 fill, jint x, jint y, jint w, jint h) {
|
||||
VKRenderer_RenderParallelogram(fill, (float) x, (float) y,
|
||||
(float) w, 0, 0,(float) h);
|
||||
}
|
||||
|
||||
void VKRenderer_RenderParallelogram(const VKRenderingContext* context, VkBool32 fill,
|
||||
void VKRenderer_RenderParallelogram(VkBool32 fill,
|
||||
jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12) {
|
||||
if (!VKRenderer_Validate(context, SHADER_COLOR,
|
||||
fill ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : VK_PRIMITIVE_TOPOLOGY_LINE_LIST)) return; // Not ready.
|
||||
Color c = context->color;
|
||||
jfloat dx12, jfloat dy12)
|
||||
{
|
||||
if (!VKRenderer_Validate(SHADER_COLOR,
|
||||
fill ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
|
||||
: VK_PRIMITIVE_TOPOLOGY_LINE_LIST, ALPHA_TYPE_UNKNOWN)) return; // Not ready.
|
||||
RGBA c = VKRenderer_GetRGBA(context.surface, context.renderColor);
|
||||
/* dx21
|
||||
* (p1)---------(p2) | (p1)------
|
||||
* |\ \ | | \ dy21
|
||||
@@ -1176,7 +1413,7 @@ void VKRenderer_RenderParallelogram(const VKRenderingContext* context, VkBool32
|
||||
VKColorVertex p4 = {x11 + dx12, y11 + dy12, c};
|
||||
|
||||
VKColorVertex* vs;
|
||||
VK_DRAW(vs, context, fill ? 6 : 8);
|
||||
VK_DRAW(vs, 1, fill ? 6 : 8);
|
||||
uint32_t i = 0;
|
||||
vs[i++] = p1;
|
||||
vs[i++] = p2;
|
||||
@@ -1190,10 +1427,10 @@ void VKRenderer_RenderParallelogram(const VKRenderingContext* context, VkBool32
|
||||
vs[i++] = p3;
|
||||
}
|
||||
|
||||
void VKRenderer_FillSpans(const VKRenderingContext* context, jint spanCount, jint *spans) {
|
||||
void VKRenderer_FillSpans(jint spanCount, jint *spans) {
|
||||
if (spanCount == 0) return;
|
||||
if (!VKRenderer_Validate(context, SHADER_COLOR, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)) return; // Not ready.
|
||||
Color c = context->color;
|
||||
if (!VKRenderer_Validate(SHADER_COLOR, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, ALPHA_TYPE_UNKNOWN)) return; // Not ready.
|
||||
RGBA c = VKRenderer_GetRGBA(context.surface, context.renderColor);
|
||||
|
||||
jfloat x1 = (float)*(spans++);
|
||||
jfloat y1 = (float)*(spans++);
|
||||
@@ -1205,7 +1442,7 @@ void VKRenderer_FillSpans(const VKRenderingContext* context, jint spanCount, jin
|
||||
VKColorVertex p4 = {x1, y2, c};
|
||||
|
||||
VKColorVertex* vs;
|
||||
VK_DRAW(vs, context, 6);
|
||||
VK_DRAW(vs, 1, 6);
|
||||
vs[0] = p1; vs[1] = p2; vs[2] = p3; vs[3] = p3; vs[4] = p4; vs[5] = p1;
|
||||
|
||||
for (int i = 1; i < spanCount; i++) {
|
||||
@@ -1214,61 +1451,19 @@ void VKRenderer_FillSpans(const VKRenderingContext* context, jint spanCount, jin
|
||||
p2.x = p3.x = (float)*(spans++);
|
||||
p3.y = p4.y = (float)*(spans++);
|
||||
|
||||
VK_DRAW(vs, context, 6);
|
||||
VK_DRAW(vs, 1, 6);
|
||||
vs[0] = p1; vs[1] = p2; vs[2] = p3; vs[3] = p3; vs[4] = p4; vs[5] = p1;
|
||||
}
|
||||
}
|
||||
|
||||
void VKRenderer_TextureRender(const VKRenderingContext* context, VKImage *destImage, VKImage *srcImage,
|
||||
VkBuffer vertexBuffer, uint32_t vertexNum) {
|
||||
if (!VKRenderer_Validate(context, SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)) return; // Not ready.
|
||||
VKSDOps* surface = (VKSDOps*)context->surface;
|
||||
void VKRenderer_TextureRender(VkDescriptorSet srcDescriptorSet, VkBuffer vertexBuffer, uint32_t vertexNum,
|
||||
jint filter, VKSamplerWrap wrap) {
|
||||
// VKRenderer_Validate was called by VKBlitLoops. TODO refactor this.
|
||||
VKSDOps* surface = (VKSDOps*)context.surface;
|
||||
VKRenderPass* renderPass = surface->renderPass;
|
||||
VkCommandBuffer cb = renderPass->commandBuffer;
|
||||
VKDevice* device = surface->device;
|
||||
|
||||
// TODO We create a new descriptor set on each command, we'll implement reusing them later.
|
||||
VkDescriptorPoolSize poolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1
|
||||
};
|
||||
VkDescriptorPoolCreateInfo descrPoolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &poolSize,
|
||||
.maxSets = 1
|
||||
};
|
||||
VkDescriptorPool descriptorPool;
|
||||
VK_IF_ERROR(device->vkCreateDescriptorPool(device->handle, &descrPoolInfo, NULL, &descriptorPool)) VK_UNHANDLED_ERROR();
|
||||
|
||||
VkDescriptorSetAllocateInfo descrAllocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = descriptorPool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &device->renderer->pipelineContext->textureDescriptorSetLayout
|
||||
};
|
||||
VkDescriptorSet descriptorSet;
|
||||
VK_IF_ERROR(device->vkAllocateDescriptorSets(device->handle, &descrAllocInfo, &descriptorSet)) VK_UNHANDLED_ERROR();
|
||||
|
||||
VkDescriptorImageInfo imageInfo = {
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.imageView = srcImage->view,
|
||||
.sampler = device->renderer->pipelineContext->linearRepeatSampler
|
||||
};
|
||||
|
||||
VkWriteDescriptorSet descriptorWrites = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = descriptorSet,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.pImageInfo = &imageInfo
|
||||
};
|
||||
|
||||
device->vkUpdateDescriptorSets(device->handle, 1, &descriptorWrites, 0, NULL);
|
||||
|
||||
|
||||
// TODO We flush all pending draws and rebind the vertex buffer with the provided one.
|
||||
// We will make it work with our unified vertex buffer later.
|
||||
VKRenderer_FlushDraw(surface);
|
||||
@@ -1276,14 +1471,17 @@ void VKRenderer_TextureRender(const VKRenderingContext* context, VKImage *destIm
|
||||
VkBuffer vertexBuffers[] = {vertexBuffer};
|
||||
VkDeviceSize offsets[] = {0};
|
||||
device->vkCmdBindVertexBuffers(cb, 0, 1, vertexBuffers, offsets);
|
||||
VkDescriptorSet descriptorSets[] = { srcDescriptorSet,
|
||||
VKSamplers_GetDescriptorSet(device, &device->renderer->pipelineContext->samplers, filter, wrap) };
|
||||
device->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
device->renderer->pipelineContext->texturePipelineLayout, 0, 1, &descriptorSet, 0, NULL);
|
||||
device->renderer->pipelineContext->texturePipelineLayout, 0, 2, descriptorSets, 0, NULL);
|
||||
device->vkCmdDraw(cb, vertexNum, 1, 0, 0);
|
||||
}
|
||||
|
||||
void VKRenderer_MaskFill(const VKRenderingContext* context, jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen, uint8_t* mask) {
|
||||
if (!VKRenderer_Validate(context, SHADER_MASK_FILL_COLOR, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)) return; // Not ready.
|
||||
void VKRenderer_MaskFill(jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen, uint8_t *mask) {
|
||||
if (!VKRenderer_Validate(SHADER_MASK_FILL_COLOR,
|
||||
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, ALPHA_TYPE_UNKNOWN)) return; // Not ready.
|
||||
// maskoff is the offset from the beginning of mask,
|
||||
// it's the same as x and y offset within a tile (maskoff % maskscan, maskoff / maskscan).
|
||||
// maskscan is the number of bytes in a row/
|
||||
@@ -1293,7 +1491,7 @@ void VKRenderer_MaskFill(const VKRenderingContext* context, jint x, jint y, jint
|
||||
maskscan = 0;
|
||||
byteCount = 1;
|
||||
}
|
||||
BufferWritingState maskState = VKRenderer_AllocateMaskFillBytes(context, byteCount);
|
||||
BufferWritingState maskState = VKRenderer_AllocateMaskFillBytes(byteCount);
|
||||
if (mask != NULL) {
|
||||
memcpy(maskState.data, mask + maskoff, byteCount);
|
||||
} else {
|
||||
@@ -1302,8 +1500,8 @@ void VKRenderer_MaskFill(const VKRenderingContext* context, jint x, jint y, jint
|
||||
}
|
||||
|
||||
VKMaskFillColorVertex* vs;
|
||||
VK_DRAW(vs, context, 6);
|
||||
Color c = context->color;
|
||||
VK_DRAW(vs, 1, 6);
|
||||
RGBA c = VKRenderer_GetRGBA(context.surface, context.renderColor);
|
||||
int offset = (int) maskState.offset;
|
||||
VKMaskFillColorVertex p1 = {x, y, offset, maskscan, c};
|
||||
VKMaskFillColorVertex p2 = {x + w, y, offset, maskscan, c};
|
||||
@@ -1314,4 +1512,56 @@ void VKRenderer_MaskFill(const VKRenderingContext* context, jint x, jint y, jint
|
||||
vs[3] = p1; vs[4] = p3; vs[5] = p4;
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
void VKRenderer_DrawImage(VKImage* image, AlphaType alphaType, VkFormat format,
|
||||
VKPackedSwizzle swizzle, jint filter, VKSamplerWrap wrap,
|
||||
float sx1, float sy1, float sx2, float sy2,
|
||||
float dx1, float dy1, float dx2, float dy2) {
|
||||
if (!VKRenderer_Validate(SHADER_BLIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, alphaType)) return;
|
||||
VKSDOps* surface = VKRenderer_GetContext()->surface;
|
||||
VKDevice* device = surface->device;
|
||||
|
||||
// Insert image barrier.
|
||||
{
|
||||
VkImageMemoryBarrier barrier;
|
||||
VKBarrierBatch barrierBatch = {};
|
||||
VKImage_AddBarrier(&barrier, &barrierBatch, image,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
VKRenderer_RecordBarriers(device->renderer, NULL, NULL, &barrier, &barrierBatch);
|
||||
}
|
||||
|
||||
// We are going to change descriptor bindings, so flush drawing.
|
||||
VKRenderer_FlushDraw(surface);
|
||||
|
||||
// Bind image & sampler descriptor sets.
|
||||
VkDescriptorSet descriptorSets[] = {
|
||||
VKImage_GetDescriptorSet(device, image, format, swizzle),
|
||||
VKSamplers_GetDescriptorSet(device, &device->renderer->pipelineContext->samplers, filter, wrap)
|
||||
};
|
||||
device->vkCmdBindDescriptorSets(surface->renderPass->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
device->renderer->pipelineContext->texturePipelineLayout, 0, 2, descriptorSets, 0, NULL);
|
||||
|
||||
// Add vertices.
|
||||
VKTxVertex* vs;
|
||||
VK_DRAW(vs, 1, 4);
|
||||
vs[0] = (VKTxVertex) {dx1, dy1, sx1, sy1};
|
||||
vs[1] = (VKTxVertex) {dx2, dy1, sx2, sy1};
|
||||
vs[2] = (VKTxVertex) {dx1, dy2, sx1, sy2};
|
||||
vs[3] = (VKTxVertex) {dx2, dy2, sx2, sy2};
|
||||
}
|
||||
|
||||
void VKRenderer_AddSurfaceDependency(VKSDOps* src, VKSDOps* dst) {
|
||||
assert(src != NULL);
|
||||
assert(dst != NULL);
|
||||
assert(dst->renderPass != NULL);
|
||||
// We don't care much about duplicates in our dependency arrays,
|
||||
// so just make a lazy deduplication attempt by checking the last element.
|
||||
if (ARRAY_SIZE(src->dependentSurfaces) == 0 || ARRAY_LAST(src->dependentSurfaces) != dst) {
|
||||
ARRAY_PUSH_BACK(src->dependentSurfaces) = dst;
|
||||
}
|
||||
if (ARRAY_SIZE(dst->renderPass->usedSurfaces) == 0 || ARRAY_LAST(dst->renderPass->usedSurfaces) != src) {
|
||||
ARRAY_PUSH_BACK(dst->renderPass->usedSurfaces) = src;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,23 @@
|
||||
#include "VKTypes.h"
|
||||
#include "VKPipelines.h"
|
||||
|
||||
#define NO_CLIP ((VkRect2D) {{0, 0}, {0x7FFFFFFFU, 0x7FFFFFFFU}})
|
||||
|
||||
struct VKRenderingContext {
|
||||
VKSDOps* surface;
|
||||
|
||||
VKTransform transform;
|
||||
uint64_t transformModCount;
|
||||
|
||||
// We keep this color separately from renderColor,
|
||||
// because we need consistent state when switching between XOR and alpha
|
||||
// composite modes. This variable holds last value set by SET_COLOR, while
|
||||
// renderColor holds color, currently used for drawing, which may have
|
||||
// also been provided by SET_XOR_COMPOSITE.
|
||||
Color color;
|
||||
Color renderColor;
|
||||
VKCompositeMode composite;
|
||||
|
||||
// Extra alpha is not used when painting with plain color,
|
||||
// in this case color.a already includes it.
|
||||
float extraAlpha;
|
||||
@@ -43,18 +55,19 @@ struct VKRenderingContext {
|
||||
ARRAY(VKIntVertex) clipSpanVertices;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t barrierCount;
|
||||
VkPipelineStageFlags srcStages;
|
||||
VkPipelineStageFlags dstStages;
|
||||
} VKBarrierBatch;
|
||||
typedef void (*VKCleanupHandler)(VKDevice *renderer, void* data);
|
||||
|
||||
VKRenderer* VKRenderer_Create(VKDevice* device);
|
||||
|
||||
/**
|
||||
* Setup pipeline for drawing. Returns FALSE if surface is not yet ready for drawing.
|
||||
*/
|
||||
VkBool32 VKRenderer_Validate(const VKRenderingContext* context, VKShader shader, VkPrimitiveTopology topology);
|
||||
VkBool32 VKRenderer_Validate(VKShader shader, VkPrimitiveTopology topology, AlphaType inAlphaType);
|
||||
|
||||
/**
|
||||
* Record draw command, if there are any pending vertices in the vertex buffer
|
||||
*/
|
||||
void VKRenderer_FlushDraw(VKSDOps* surface);
|
||||
|
||||
/**
|
||||
* Record commands into primary command buffer (outside of a render pass).
|
||||
@@ -68,6 +81,19 @@ VkCommandBuffer VKRenderer_Record(VKRenderer* renderer);
|
||||
void VKRenderer_AddImageBarrier(VkImageMemoryBarrier* barriers, VKBarrierBatch* batch,
|
||||
VKImage* image, VkPipelineStageFlags stage, VkAccessFlags access, VkImageLayout layout);
|
||||
|
||||
void VKRenderer_AddBufferBarrier(VkBufferMemoryBarrier* barriers, VKBarrierBatch* batch,
|
||||
VKBuffer* buffer, VkPipelineStageFlags stage,
|
||||
VkAccessFlags access);
|
||||
|
||||
/**
|
||||
* Record barrier batches into the primary command buffer.
|
||||
*/
|
||||
void VKRenderer_RecordBarriers(VKRenderer* renderer,
|
||||
VkBufferMemoryBarrier* bufferBarriers, VKBarrierBatch* bufferBatch,
|
||||
VkImageMemoryBarrier* imageBarriers, VKBarrierBatch* imageBatch);
|
||||
|
||||
void VKRenderer_CreateImageDescriptorSet(VKRenderer* renderer, VkDescriptorPool* descriptorPool, VkDescriptorSet* set);
|
||||
|
||||
void VKRenderer_Destroy(VKRenderer* renderer);
|
||||
|
||||
/**
|
||||
@@ -85,6 +111,17 @@ void VKRenderer_Flush(VKRenderer* renderer);
|
||||
*/
|
||||
void VKRenderer_DestroyRenderPass(VKSDOps* surface);
|
||||
|
||||
/**
|
||||
* End render pass for the surface and record it into the primary command buffer,
|
||||
* which will be executed on the next VKRenderer_Flush.
|
||||
*/
|
||||
VkBool32 VKRenderer_FlushRenderPass(VKSDOps* surface);
|
||||
|
||||
/**
|
||||
* Register a handler to be called at the cleanup phase of the renderer.
|
||||
*/
|
||||
void VKRenderer_DisposeOnCleanup(VKRenderer* renderer, VKCleanupHandler hnd, void* data);
|
||||
|
||||
/**
|
||||
* Flush pending render pass and queue surface for presentation (if applicable).
|
||||
*/
|
||||
@@ -94,33 +131,34 @@ void VKRenderer_FlushSurface(VKSDOps* surface);
|
||||
* Request size for the surface. It has no effect, if it is already of the same size.
|
||||
* Actual resize will be performed later, before starting a new frame.
|
||||
*/
|
||||
void VKRenderer_ConfigureSurface(VKSDOps* surface, VkExtent2D extent);
|
||||
void VKRenderer_ConfigureSurface(VKSDOps* surface, VkExtent2D extent, VKDevice* device);
|
||||
|
||||
/**
|
||||
* End render pass for the surface and record it into the primary command buffer,
|
||||
* which will be executed on the next VKRenderer_Flush.
|
||||
*/
|
||||
void VKRenderer_FlushRenderPass(VKSDOps* surface);
|
||||
void VKRenderer_AddSurfaceDependency(VKSDOps* src, VKSDOps* dst);
|
||||
|
||||
// Blit operations.
|
||||
|
||||
void VKRenderer_TextureRender(const VKRenderingContext* context,
|
||||
VKImage *destImage, VKImage *srcImage,
|
||||
VkBuffer vertexBuffer, uint32_t vertexNum);
|
||||
void VKRenderer_TextureRender(VkDescriptorSet srcDescriptorSet, VkBuffer vertexBuffer, uint32_t vertexNum,
|
||||
jint filter, VKSamplerWrap wrap);
|
||||
|
||||
// Drawing operations.
|
||||
|
||||
void VKRenderer_RenderRect(const VKRenderingContext* context, VkBool32 fill,
|
||||
jint x, jint y, jint w, jint h);
|
||||
void VKRenderer_RenderRect(VkBool32 fill, jint x, jint y, jint w, jint h);
|
||||
|
||||
void VKRenderer_RenderParallelogram(const VKRenderingContext* context, VkBool32 fill,
|
||||
void VKRenderer_RenderParallelogram(VkBool32 fill,
|
||||
jfloat x11, jfloat y11,
|
||||
jfloat dx21, jfloat dy21,
|
||||
jfloat dx12, jfloat dy12);
|
||||
|
||||
void VKRenderer_FillSpans(const VKRenderingContext* context, jint spanCount, jint *spans);
|
||||
void VKRenderer_FillSpans(jint spanCount, jint *spans);
|
||||
|
||||
void VKRenderer_MaskFill(const VKRenderingContext* context,
|
||||
jint x, jint y, jint w, jint h, jint maskoff, jint maskscan, jint masklen, uint8_t* mask);
|
||||
void VKRenderer_MaskFill(jint x, jint y, jint w, jint h,
|
||||
jint maskoff, jint maskscan, jint masklen, uint8_t *mask);
|
||||
|
||||
void VKRenderer_DrawImage(VKImage* image, AlphaType alphaType, VkFormat format,
|
||||
VKPackedSwizzle swizzle, jint filter, VKSamplerWrap wrap,
|
||||
float sx1, float sy1, float sx2, float sy2,
|
||||
float dx1, float dy1, float dx2, float dy2);
|
||||
|
||||
VKRenderingContext* VKRenderer_GetContext();
|
||||
|
||||
#endif //VKRenderer_h_Included
|
||||
|
||||
145
src/java.desktop/share/native/common/java2d/vulkan/VKSamplers.c
Normal file
145
src/java.desktop/share/native/common/java2d/vulkan/VKSamplers.c
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright 2025 JetBrains s.r.o.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License version 2 only, as
|
||||
// published by the Free Software Foundation. Oracle designates this
|
||||
// particular file as subject to the "Classpath" exception as provided
|
||||
// by Oracle in the LICENSE file that accompanied this code.
|
||||
//
|
||||
// This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// version 2 for more details (a copy is included in the LICENSE file that
|
||||
// accompanied this code).
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License version
|
||||
// 2 along with this work; if not, write to the Free Software Foundation,
|
||||
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
|
||||
#include <assert.h>
|
||||
#include "VKDevice.h"
|
||||
#include "VKSamplers.h"
|
||||
|
||||
VKSamplers VKSamplers_Create(VKDevice* device) {
|
||||
VKSamplers result = {};
|
||||
// Create descriptor pool.
|
||||
uint32_t size = SAMPLER_FILTER_COUNT * SAMPLER_WRAP_COUNT;
|
||||
VkDescriptorPoolSize poolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_SAMPLER,
|
||||
.descriptorCount = size
|
||||
};
|
||||
VkDescriptorPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &poolSize,
|
||||
.maxSets = size
|
||||
};
|
||||
VK_IF_ERROR(device->vkCreateDescriptorPool(device->handle, &poolInfo, NULL, &result.descriptorPool)) {
|
||||
return (VKSamplers) {};
|
||||
}
|
||||
// Create descriptor set layout.
|
||||
VkDescriptorSetLayoutBinding descriptorSetLayoutBinding = {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.pImmutableSamplers = NULL
|
||||
};
|
||||
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindings = &descriptorSetLayoutBinding
|
||||
};
|
||||
VK_IF_ERROR(device->vkCreateDescriptorSetLayout(device->handle, &descriptorSetLayoutCreateInfo, NULL, &result.descriptorSetLayout)) {
|
||||
VKSamplers_Destroy(device, result);
|
||||
return (VKSamplers) {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void VKSamplers_Destroy(VKDevice* device, VKSamplers samplers) {
|
||||
device->vkDestroyDescriptorPool(device->handle, samplers.descriptorPool, NULL);
|
||||
device->vkDestroyDescriptorSetLayout(device->handle, samplers.descriptorSetLayout, NULL);
|
||||
for (jint filter = 0; filter < SAMPLER_FILTER_COUNT; filter++) {
|
||||
for (VKSamplerWrap wrap = 0; wrap < SAMPLER_WRAP_COUNT; wrap++) {
|
||||
device->vkDestroySampler(device->handle, samplers.table[filter][wrap].sampler, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VkDescriptorSet VKSamplers_GetDescriptorSet(VKDevice* device, VKSamplers* samplers, jint filter, VKSamplerWrap wrap) {
|
||||
assert(device != NULL && samplers != NULL);
|
||||
assert(filter > 0 && filter <= SAMPLER_FILTER_COUNT);
|
||||
assert(wrap >= 0 && wrap < SAMPLER_WRAP_COUNT);
|
||||
if (samplers->table[filter-1][wrap].descriptorSet == VK_NULL_HANDLE) {
|
||||
// Resolve filtering mode.
|
||||
VkFilter filterMode;
|
||||
switch (filter) {
|
||||
case java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR:
|
||||
filterMode = VK_FILTER_NEAREST;
|
||||
break;
|
||||
case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
|
||||
filterMode = VK_FILTER_LINEAR;
|
||||
break;
|
||||
case java_awt_image_AffineTransformOp_TYPE_BICUBIC:
|
||||
filterMode = VK_FILTER_CUBIC_EXT;
|
||||
assert(false); // Cubic filter is currently not supported, see VK_EXT_filter_cubic.
|
||||
break;
|
||||
default: return VK_NULL_HANDLE;
|
||||
}
|
||||
// Resolve address mode.
|
||||
VkSamplerAddressMode addressMode;
|
||||
switch (wrap) {
|
||||
case SAMPLER_WRAP_BORDER:
|
||||
addressMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
break;
|
||||
case SAMPLER_WRAP_REPEAT:
|
||||
addressMode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
break;
|
||||
default: return VK_NULL_HANDLE;
|
||||
}
|
||||
// Create sampler.
|
||||
VkSamplerCreateInfo samplerCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = filterMode,
|
||||
.minFilter = filterMode,
|
||||
.addressModeU = addressMode,
|
||||
.addressModeV = addressMode,
|
||||
.addressModeW = addressMode,
|
||||
.unnormalizedCoordinates = VK_TRUE
|
||||
};
|
||||
VK_IF_ERROR(device->vkCreateSampler(device->handle, &samplerCreateInfo, NULL, &samplers->table[filter-1][wrap].sampler)) {
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
// Create descriptor set.
|
||||
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = samplers->descriptorPool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &samplers->descriptorSetLayout
|
||||
};
|
||||
VK_IF_ERROR(device->vkAllocateDescriptorSets(device->handle, &descriptorSetAllocateInfo,
|
||||
&samplers->table[filter-1][wrap].descriptorSet)) {
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
VkDescriptorImageInfo samplerImageInfo = {
|
||||
.sampler = samplers->table[filter-1][wrap].sampler
|
||||
};
|
||||
VkWriteDescriptorSet descriptorWrites = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = samplers->table[filter-1][wrap].descriptorSet,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.pImageInfo = &samplerImageInfo
|
||||
};
|
||||
device->vkUpdateDescriptorSets(device->handle, 1, &descriptorWrites, 0, NULL);
|
||||
}
|
||||
return samplers->table[filter-1][wrap].descriptorSet;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2025 JetBrains s.r.o.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License version 2 only, as
|
||||
// published by the Free Software Foundation. Oracle designates this
|
||||
// particular file as subject to the "Classpath" exception as provided
|
||||
// by Oracle in the LICENSE file that accompanied this code.
|
||||
//
|
||||
// This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// version 2 for more details (a copy is included in the LICENSE file that
|
||||
// accompanied this code).
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License version
|
||||
// 2 along with this work; if not, write to the Free Software Foundation,
|
||||
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
|
||||
#ifndef VKSamplers_h_Included
|
||||
#define VKSamplers_h_Included
|
||||
|
||||
#include "java_awt_image_AffineTransformOp.h"
|
||||
#include "VKUtil.h"
|
||||
|
||||
// Filter types in Java are numbered from 1
|
||||
// Cubic filter is currently not supported, see VK_EXT_filter_cubic.
|
||||
#define SAMPLER_FILTER_COUNT java_awt_image_AffineTransformOp_TYPE_BILINEAR
|
||||
|
||||
typedef enum {
|
||||
SAMPLER_WRAP_BORDER = 0,
|
||||
SAMPLER_WRAP_REPEAT = 1,
|
||||
SAMPLER_WRAP_COUNT = 2
|
||||
} VKSamplerWrap;
|
||||
|
||||
typedef struct {
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
struct {
|
||||
VkSampler sampler;
|
||||
VkDescriptorSet descriptorSet;
|
||||
} table[SAMPLER_FILTER_COUNT][SAMPLER_WRAP_COUNT];
|
||||
} VKSamplers;
|
||||
|
||||
VKSamplers VKSamplers_Create(VKDevice* device);
|
||||
void VKSamplers_Destroy(VKDevice* device, VKSamplers samplers);
|
||||
VkDescriptorSet VKSamplers_GetDescriptorSet(VKDevice* device, VKSamplers* samplers, jint filter, VKSamplerWrap wrap);
|
||||
|
||||
#endif //VKSamplers_h_Included
|
||||
@@ -30,13 +30,25 @@
|
||||
#include "jni.h"
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKInstance
|
||||
* Method: init
|
||||
* Signature: (JZI)Z
|
||||
* Class: sun_java2d_vulkan_VKEnv
|
||||
* Method: initPlatform
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_java2d_vulkan_VKInstance_initNative(JNIEnv *env, jclass wlge, jlong nativePtr, jboolean verb, jint requestedDevice) {
|
||||
Java_sun_java2d_vulkan_VKEnv_initPlatform(JNIEnv *env, jclass wlge, jlong nativePtr) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKEnv
|
||||
* Method: initNative
|
||||
* Signature: (J)[Lsun/java2d/vulkan/VKGPU;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_java2d_vulkan_VKEnv_initNative
|
||||
(JNIEnv *env, jclass cls, jlong platformData)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -24,12 +24,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESS
|
||||
|
||||
#include "VKUtil.h"
|
||||
#include "VKBase.h"
|
||||
#include "VKRenderer.h"
|
||||
#include "VKSurfaceData.h"
|
||||
#include "VKImage.h"
|
||||
#include "VKEnv.h"
|
||||
|
||||
/**
|
||||
* Release VKSDOps resources & reset to initial state.
|
||||
@@ -37,8 +36,11 @@
|
||||
static void VKSD_ResetImageSurface(VKSDOps* vksdo) {
|
||||
if (vksdo == NULL) return;
|
||||
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_ResetImageSurface(%p)", vksdo);
|
||||
|
||||
// DestroyRenderPass also waits while the surface resources are being used by device.
|
||||
VKRenderer_DestroyRenderPass(vksdo);
|
||||
vksdo->lastTimestamp = 0;
|
||||
|
||||
if (vksdo->device != NULL) {
|
||||
VKImage_Destroy(vksdo->device, vksdo->stencil);
|
||||
@@ -59,8 +61,8 @@ void VKSD_ResetSurface(VKSDOps* vksdo) {
|
||||
vkwinsdo->vksdOps.device->vkDestroySwapchainKHR(vkwinsdo->vksdOps.device->handle, vkwinsdo->swapchain, NULL);
|
||||
}
|
||||
if (vkwinsdo->surface != VK_NULL_HANDLE) {
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
if (ge != NULL) ge->vkDestroySurfaceKHR(ge->vkInstance, vkwinsdo->surface, NULL);
|
||||
VKEnv* vk = VKEnv_GetInstance();
|
||||
vk->vkDestroySurfaceKHR(vk->instance, vkwinsdo->surface, NULL);
|
||||
}
|
||||
vkwinsdo->swapchain = VK_NULL_HANDLE;
|
||||
vkwinsdo->surface = VK_NULL_HANDLE;
|
||||
@@ -73,8 +75,9 @@ static void VKSD_FindImageSurfaceMemoryType(VKMemoryRequirements* requirements)
|
||||
}
|
||||
|
||||
VkBool32 VKSD_ConfigureImageSurface(VKSDOps* vksdo) {
|
||||
// Initialize the device. currentDevice can be changed on the fly, and we must reconfigure surfaces accordingly.
|
||||
VKDevice* device = VKGE_graphics_environment()->currentDevice;
|
||||
// Initialize the device. current device can be changed on the fly, and we must reconfigure surfaces accordingly.
|
||||
VKDevice* device = vksdo->requestedDevice;
|
||||
if (device == NULL) return VK_FALSE;
|
||||
if (device != vksdo->device) {
|
||||
VKSD_ResetImageSurface(vksdo);
|
||||
vksdo->device = device;
|
||||
@@ -84,10 +87,9 @@ VkBool32 VKSD_ConfigureImageSurface(VKSDOps* vksdo) {
|
||||
if (vksdo->requestedExtent.width > 0 && vksdo->requestedExtent.height > 0 && (vksdo->image == NULL ||
|
||||
vksdo->requestedExtent.width != vksdo->image->extent.width ||
|
||||
vksdo->requestedExtent.height != vksdo->image->extent.height)) {
|
||||
// VK_FORMAT_B8G8R8A8_UNORM is the most widely-supported format for our use.
|
||||
// Currently, we only support *_SRGB and *_UNORM formats,
|
||||
// as other types may not be trivial to alias for logicOp rendering.
|
||||
VkFormat format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
VkFormat format = (VkFormat) (vksdo->drawableFormat & ~VKSD_FORMAT_OPAQUE_BIT);
|
||||
|
||||
VKImage* image = VKImage_Create(device, vksdo->requestedExtent.width, vksdo->requestedExtent.height,
|
||||
0, format, VK_IMAGE_TILING_OPTIMAL,
|
||||
@@ -137,12 +139,12 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VKGraphicsEnvironment* ge = VKGE_graphics_environment();
|
||||
VKEnv* vk = VKEnv_GetInstance();
|
||||
VKDevice* device = vkwinsdo->vksdOps.device;
|
||||
VkPhysicalDevice physicalDevice = device->physicalDevice;
|
||||
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, vkwinsdo->surface, &capabilities)) {
|
||||
VK_IF_ERROR(vk->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, vkwinsdo->surface, &capabilities)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
@@ -188,11 +190,11 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
} else compositeAlpha = (VkCompositeAlphaFlagBitsKHR) capabilities.supportedCompositeAlpha;
|
||||
|
||||
uint32_t formatCount;
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &formatCount, NULL)) {
|
||||
VK_IF_ERROR(vk->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &formatCount, NULL)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
VkSurfaceFormatKHR formats[formatCount];
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &formatCount, formats)) {
|
||||
VK_IF_ERROR(vk->vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, vkwinsdo->surface, &formatCount, formats)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
@@ -203,13 +205,8 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
// We draw with sRGB colors (see VKUtil_DecodeJavaColor()), so we don't want Vulkan to do color space
|
||||
// conversions when drawing to surface. We use *_UNORM formats, so that colors are written "as is".
|
||||
// With VK_COLOR_SPACE_SRGB_NONLINEAR_KHR these colors will be interpreted by presentation engine as sRGB.
|
||||
if (formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR && (
|
||||
formats[i].format == VK_FORMAT_A8B8G8R8_UNORM_PACK32 ||
|
||||
formats[i].format == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_R8G8B8A8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_B8G8R8_UNORM ||
|
||||
formats[i].format == VK_FORMAT_R8G8B8_UNORM
|
||||
)) {
|
||||
if (formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
|
||||
formats[i].format == vkwinsdo->vksdOps.image->format) {
|
||||
format = &formats[i];
|
||||
}
|
||||
}
|
||||
@@ -219,11 +216,11 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &presentModeCount, NULL)) {
|
||||
VK_IF_ERROR(vk->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &presentModeCount, NULL)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
VkPresentModeKHR presentModes[presentModeCount];
|
||||
VK_IF_ERROR(ge->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &presentModeCount, presentModes)) {
|
||||
VK_IF_ERROR(vk->vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, vkwinsdo->surface, &presentModeCount, presentModes)) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
// FIFO mode is guaranteed to be supported.
|
||||
@@ -262,7 +259,7 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
.compositeAlpha = compositeAlpha,
|
||||
.presentMode = presentMode,
|
||||
.clipped = VK_TRUE,
|
||||
.oldSwapchain = vkwinsdo->swapchain
|
||||
.oldSwapchain = vkwinsdo->swapchainDevice == device ? vkwinsdo->swapchain : NULL
|
||||
};
|
||||
|
||||
VK_IF_ERROR(device->vkCreateSwapchainKHR(device->handle, &createInfoKhr, NULL, &swapchain)) {
|
||||
@@ -275,7 +272,7 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
if (vkwinsdo->swapchain != VK_NULL_HANDLE) {
|
||||
// Destroy old swapchain.
|
||||
// TODO is it possible that old swapchain is still being presented, can we destroy it right now?
|
||||
device->vkDestroySwapchainKHR(device->handle, vkwinsdo->swapchain, NULL);
|
||||
device->vkDestroySwapchainKHR(vkwinsdo->swapchainDevice->handle, vkwinsdo->swapchain, NULL);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_ConfigureWindowSurface(%p): old swapchain destroyed", vkwinsdo);
|
||||
}
|
||||
vkwinsdo->swapchain = swapchain;
|
||||
@@ -294,23 +291,61 @@ VkBool32 VKSD_ConfigureWindowSurface(VKWinSDOps* vkwinsdo) {
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
static void VKSD_OnDispose(JNIEnv* env, SurfaceDataOps* ops) {
|
||||
VKSD_ResetSurface((VKSDOps*) ops);
|
||||
}
|
||||
|
||||
JNIEXPORT VKSDOps* VKSD_CreateSurface(JNIEnv* env, jobject vksd, jint type, jint format, jint backgroundRGB,
|
||||
VKWinSD_SurfaceResizeCallback resizeCallback) {
|
||||
VKSDOps* sd = (VKSDOps*)SurfaceData_InitOps(env, vksd,
|
||||
type == VKSD_WINDOW ? sizeof(VKWinSDOps) : sizeof(VKSDOps));
|
||||
J2dTraceLn3(J2D_TRACE_INFO,
|
||||
"VKSD_CreateSurface(%p): type=%d, format=%d", sd, type, format & ~VKSD_FORMAT_OPAQUE_BIT);
|
||||
if (sd == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Initialization of VKSDOps failed");
|
||||
return NULL;
|
||||
}
|
||||
sd->sdOps.Dispose = VKSD_OnDispose;
|
||||
sd->drawableType = type;
|
||||
sd->drawableFormat = format;
|
||||
sd->background = VKUtil_DecodeJavaColor(backgroundRGB, ALPHA_TYPE_STRAIGHT);
|
||||
sd->lastTimestamp = 0;
|
||||
if (type == VKSD_WINDOW) {
|
||||
VKWinSDOps* winSD = (VKWinSDOps*) sd;
|
||||
winSD->resizeCallback = resizeCallback;
|
||||
}
|
||||
VKSD_ResetSurface(sd);
|
||||
return sd;
|
||||
}
|
||||
|
||||
JNIEXPORT void VKSD_InitWindowSurface(JNIEnv* env, jobject vksd, VKWinSD_SurfaceInitCallback initCallback, void* data) {
|
||||
VKWinSDOps* sd = (VKWinSDOps*)SurfaceData_GetOps(env, vksd);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_InitWindowSurface(%p)", sd);
|
||||
|
||||
if (sd == NULL) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, "VKSD_InitWindowSurface(%p): VKWinSDOps is NULL", vksd);
|
||||
VK_UNHANDLED_ERROR();
|
||||
}
|
||||
|
||||
if (sd->surface != VK_NULL_HANDLE) {
|
||||
VKSD_ResetSurface(&sd->vksdOps);
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_InitWindowSurface(%p): surface reset", vksd);
|
||||
}
|
||||
|
||||
initCallback(sd, data);
|
||||
|
||||
if (sd->surface != VK_NULL_HANDLE) {
|
||||
J2dRlsTraceLn1(J2D_TRACE_INFO, "VKSD_InitWindowSurface(%p): surface created", vksd);
|
||||
}
|
||||
// Swapchain will be created later after CONFIGURE_SURFACE.
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_java2d_vulkan_VKOffScreenSurfaceData
|
||||
* Method: initOps
|
||||
* Signature: (II)V
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKOffScreenSurfaceData_initOps
|
||||
(JNIEnv *env, jobject vksd, jint width, jint height) {
|
||||
VKSDOps * sd = (VKSDOps*)SurfaceData_InitOps(env, vksd, sizeof(VKSDOps));
|
||||
J2dTraceLn1(J2D_TRACE_VERBOSE, "VKOffScreenSurfaceData_initOps(%p)", sd);
|
||||
if (sd == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
|
||||
return;
|
||||
}
|
||||
sd->drawableType = VKSD_RT_TEXTURE;
|
||||
sd->background = VKUtil_DecodeJavaColor(0);
|
||||
VKSD_ResetSurface(sd);
|
||||
VKRenderer_ConfigureSurface(sd, (VkExtent2D){width, height});
|
||||
JNIEXPORT void JNICALL Java_sun_java2d_vulkan_VKOffScreenSurfaceData_initOps(JNIEnv* env, jobject vksd, jint format) {
|
||||
VKSD_CreateSurface(env, vksd, VKSD_RT_TEXTURE, format, 0, NULL);
|
||||
}
|
||||
|
||||
#endif /* !HEADLESS */
|
||||
|
||||
@@ -30,17 +30,11 @@
|
||||
#include "SurfaceData.h"
|
||||
#include "sun_java2d_pipe_hw_AccelSurface.h"
|
||||
#include "VKUtil.h"
|
||||
#include "VKTypes.h"
|
||||
#include "VKRenderer.h"
|
||||
|
||||
/**
|
||||
* These are shorthand names for the surface type constants defined in
|
||||
* VKSurfaceData.java.
|
||||
* TODO which constants?
|
||||
*/
|
||||
#define VKSD_UNDEFINED sun_java2d_pipe_hw_AccelSurface_UNDEFINED
|
||||
#define VKSD_WINDOW sun_java2d_pipe_hw_AccelSurface_WINDOW
|
||||
#define VKSD_RT_TEXTURE sun_java2d_pipe_hw_AccelSurface_RT_TEXTURE
|
||||
#define VKSD_FORMAT_OPAQUE_BIT ((jint) 0x80000000)
|
||||
|
||||
/**
|
||||
* The VKSDOps structure describes a native Vulkan surface and contains all
|
||||
@@ -49,17 +43,23 @@
|
||||
struct VKSDOps {
|
||||
SurfaceDataOps sdOps;
|
||||
jint drawableType;
|
||||
jint drawableFormat;
|
||||
VKDevice* device;
|
||||
VKImage* image;
|
||||
VKImage* stencil;
|
||||
|
||||
Color background;
|
||||
VkExtent2D requestedExtent;
|
||||
VKDevice* requestedDevice;
|
||||
|
||||
VKRenderPass* renderPass;
|
||||
|
||||
ARRAY(VKSDOps*) dependentSurfaces; // Whose pending render passes read from the surface.
|
||||
uint64_t lastTimestamp; // When was this surface last used?
|
||||
};
|
||||
|
||||
typedef void (*VKWinSD_SurfaceResizeCallback)(VKWinSDOps* surface, VkExtent2D extent);
|
||||
typedef void (*VKWinSD_SurfaceInitCallback)(VKWinSDOps* surface, void* data);
|
||||
|
||||
/**
|
||||
* The VKWinSDOps structure describes a native Vulkan surface connected with a window.
|
||||
@@ -74,10 +74,26 @@ struct VKWinSDOps {
|
||||
VKWinSD_SurfaceResizeCallback resizeCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new surface with given parameters.
|
||||
* This is intended to be called via JNI and provided with a valid VKSurfaceData object handle.
|
||||
* Use SurfaceData_DisposeOps to destroy the surface.
|
||||
*/
|
||||
JNIEXPORT VKSDOps* VKSD_CreateSurface(JNIEnv* env, jobject vksd, jint drawableType, jint format, jint backgroundRGB,
|
||||
VKWinSD_SurfaceResizeCallback resizeCallback);
|
||||
|
||||
/**
|
||||
* [Re]initialize window surface with a given platform-specific initialization callback.
|
||||
* This is intended to be called via JNI and provided with a valid VKSurfaceData object handle.
|
||||
*/
|
||||
JNIEXPORT void VKSD_InitWindowSurface(JNIEnv *env, jobject vksd, VKWinSD_SurfaceInitCallback initCallback, void* data);
|
||||
|
||||
inline VkBool32 VKSD_IsOpaque(VKSDOps* vksdo) {
|
||||
return vksdo->drawableFormat & VKSD_FORMAT_OPAQUE_BIT ? VK_TRUE : VK_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release all resources of the surface, resetting it to initial state.
|
||||
* This function must also be used to initialize newly allocated surfaces.
|
||||
* VKSDOps.drawableType must be properly set before calling this function.
|
||||
*/
|
||||
void VKSD_ResetSurface(VKSDOps* vksdo);
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ void VKTexturePoolHandle_ReleaseTexture(VKTexturePoolHandle *handle) {
|
||||
ATexturePoolHandle_ReleaseTexture(handle);
|
||||
}
|
||||
|
||||
ATexturePrivPtr* VKTexturePoolHandle_GetTexture(VKTexturePoolHandle *handle) {
|
||||
VKImage* VKTexturePoolHandle_GetTexture(VKTexturePoolHandle *handle) {
|
||||
return ATexturePoolHandle_GetTexture(handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "AccelTexturePool.h"
|
||||
#include "jni.h"
|
||||
#include "VKTypes.h"
|
||||
|
||||
|
||||
/* VKTexturePoolHandle API */
|
||||
@@ -36,7 +37,7 @@ typedef ATexturePoolHandle VKTexturePoolHandle;
|
||||
|
||||
void VKTexturePoolHandle_ReleaseTexture(VKTexturePoolHandle *handle);
|
||||
|
||||
ATexturePrivPtr* VKTexturePoolHandle_GetTexture(VKTexturePoolHandle *handle);
|
||||
VKImage* VKTexturePoolHandle_GetTexture(VKTexturePoolHandle *handle);
|
||||
|
||||
jint VKTexturePoolHandle_GetRequestedWidth(VKTexturePoolHandle *handle);
|
||||
jint VKTexturePoolHandle_GetRequestedHeight(VKTexturePoolHandle *handle);
|
||||
|
||||
@@ -23,18 +23,37 @@
|
||||
|
||||
#ifndef VKTypes_h_Included
|
||||
#define VKTypes_h_Included
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
typedef enum {
|
||||
ALPHA_TYPE_PRE_MULTIPLIED = 0,
|
||||
ALPHA_TYPE_STRAIGHT = 1,
|
||||
ALPHA_TYPE_UNKNOWN = ALPHA_TYPE_PRE_MULTIPLIED // Fallback to pre-multiplied.
|
||||
} AlphaType;
|
||||
|
||||
/**
|
||||
* Floating-point RGBA color with sRGB encoding and pre-multiplied alpha.
|
||||
* Floating-point RGBA color in unspecified color space and alpha type.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
float r, g, b, a;
|
||||
};
|
||||
VkClearValue vkClearValue;
|
||||
} RGBA;
|
||||
|
||||
/**
|
||||
* Floating-point encoding-agnostic color.
|
||||
*/
|
||||
typedef struct {
|
||||
RGBA values[ALPHA_TYPE_STRAIGHT+1];
|
||||
} Color;
|
||||
|
||||
/**
|
||||
* VkComponentMapping packed into 12 bits.
|
||||
*/
|
||||
typedef uint16_t VKPackedSwizzle;
|
||||
|
||||
/**
|
||||
* Transform matrix
|
||||
* [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
|
||||
@@ -42,13 +61,13 @@ typedef union {
|
||||
* [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
|
||||
*/
|
||||
typedef struct {
|
||||
double m00, m01, m02;
|
||||
double m10, m11, m12;
|
||||
float m00, m01, m02;
|
||||
float m10 __attribute__((aligned(16))), m11, m12;
|
||||
} VKTransform;
|
||||
|
||||
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VKMemory);
|
||||
|
||||
typedef struct VKGraphicsEnvironment VKGraphicsEnvironment;
|
||||
typedef struct VKEnv VKEnv;
|
||||
typedef struct VKDevice VKDevice;
|
||||
typedef struct VKAllocator VKAllocator;
|
||||
typedef struct VKRenderer VKRenderer;
|
||||
@@ -62,6 +81,6 @@ typedef struct VKImage VKImage;
|
||||
typedef struct VKSDOps VKSDOps;
|
||||
typedef struct VKWinSDOps VKWinSDOps;
|
||||
|
||||
typedef char* pchar;
|
||||
typedef const char* pchar;
|
||||
|
||||
#endif //VKTypes_h_Included
|
||||
|
||||
@@ -22,10 +22,20 @@
|
||||
// questions.
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "VKUtil.h"
|
||||
|
||||
Color VKUtil_DecodeJavaColor(uint32_t color) {
|
||||
assert(sizeof(Color) == sizeof(float) * 4);
|
||||
static RGBA VKUtil_ConvertAlphaType(RGBA rgba, AlphaType newAlphaType) {
|
||||
float mul = rgba.a;
|
||||
if (newAlphaType == ALPHA_TYPE_STRAIGHT && mul != 0.0f) mul = 1.0f / mul;
|
||||
rgba.r *= mul;
|
||||
rgba.g *= mul;
|
||||
rgba.b *= mul;
|
||||
return rgba;
|
||||
}
|
||||
|
||||
Color VKUtil_DecodeJavaColor(uint32_t color, AlphaType alphaType) {
|
||||
assert(sizeof(RGBA) == sizeof(float) * 4);
|
||||
// Just map [0, 255] integer colors onto [0, 1] floating-point range, it remains in sRGB color space.
|
||||
// sRGB gamma correction remains unsupported.
|
||||
static const float NormTable256[256] = {
|
||||
@@ -34,17 +44,25 @@ Color VKUtil_DecodeJavaColor(uint32_t color) {
|
||||
#define NORM64(N) NORM8(N),NORM8(N+8),NORM8(N+16),NORM8(N+24),NORM8(N+32),NORM8(N+40),NORM8(N+48),NORM8(N+56)
|
||||
NORM64(0),NORM64(64),NORM64(128),NORM64(192)
|
||||
};
|
||||
Color srgb = {
|
||||
.r = NormTable256[(color >> 16) & 0xFF],
|
||||
.g = NormTable256[(color >> 8) & 0xFF],
|
||||
.b = NormTable256[ color & 0xFF],
|
||||
.a = NormTable256[(color >> 24) & 0xFF]
|
||||
// Decode color in its original type.
|
||||
static const RGBA NAN_RGBA = {.r = NAN, .g = NAN, .b = NAN, .a = NAN};
|
||||
Color result = {{ NAN_RGBA, NAN_RGBA }};
|
||||
result.values[alphaType] = (RGBA) {
|
||||
.r = NormTable256[(color >> 16) & 0xFF],
|
||||
.g = NormTable256[(color >> 8) & 0xFF],
|
||||
.b = NormTable256[ color & 0xFF],
|
||||
.a = NormTable256[(color >> 24) & 0xFF]
|
||||
};
|
||||
// Convert to pre-multiplied alpha.
|
||||
srgb.r *= srgb.a;
|
||||
srgb.g *= srgb.a;
|
||||
srgb.b *= srgb.a;
|
||||
return srgb;
|
||||
return result;
|
||||
}
|
||||
|
||||
RGBA VKUtil_GetRGBA(Color color, AlphaType alphaType) {
|
||||
if (isnan(color.values[alphaType].a)) {
|
||||
AlphaType otherAlphaType = alphaType ^ 1;
|
||||
assert(!isnan(color.values[otherAlphaType].a));
|
||||
color.values[alphaType] = VKUtil_ConvertAlphaType(color.values[otherAlphaType], alphaType);
|
||||
}
|
||||
return color.values[alphaType];
|
||||
}
|
||||
|
||||
uint32_t VKUtil_Log2(uint64_t i) {
|
||||
@@ -55,27 +73,28 @@ uint32_t VKUtil_Log2(uint64_t i) {
|
||||
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
|
||||
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) };
|
||||
register uint32_t t;
|
||||
if (t = i >> 56) return 56 + LogTable256[t];
|
||||
else if (t = i >> 48) return 48 + LogTable256[t];
|
||||
else if (t = i >> 40) return 40 + LogTable256[t];
|
||||
else if (t = i >> 32) return 32 + LogTable256[t];
|
||||
else if (t = i >> 24) return 24 + LogTable256[t];
|
||||
else if (t = i >> 16) return 16 + LogTable256[t];
|
||||
else if (t = i >> 8) return 8 + LogTable256[t];
|
||||
else return LogTable256[i & 0xFF];
|
||||
if ((t = i >> 56)) return 56 + LogTable256[t];
|
||||
if ((t = i >> 48)) return 48 + LogTable256[t];
|
||||
if ((t = i >> 40)) return 40 + LogTable256[t];
|
||||
if ((t = i >> 32)) return 32 + LogTable256[t];
|
||||
if ((t = i >> 24)) return 24 + LogTable256[t];
|
||||
if ((t = i >> 16)) return 16 + LogTable256[t];
|
||||
if ((t = i >> 8)) return 8 + LogTable256[t];
|
||||
return LogTable256[i & 0xFF];
|
||||
}
|
||||
|
||||
FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
#define GROUP(SIZE, ...) return ((FormatGroup) { .bytes = SIZE, .aliases[FORMAT_ALIAS_ORIGINAL] = format, __VA_ARGS__ })
|
||||
#define GROUP(ASPECT, SIZE, ...) return ((FormatGroup) { \
|
||||
.bytes = SIZE, .aspect = VK_IMAGE_ASPECT_ ## ASPECT ## _BIT, .aliases[FORMAT_ALIAS_ORIGINAL] = format, __VA_ARGS__ })
|
||||
switch (format) {
|
||||
case VK_FORMAT_R4G4_UNORM_PACK8: GROUP(1, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R4G4_UNORM_PACK8);
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R4G4B4A4_UNORM_PACK16);
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B4G4R4A4_UNORM_PACK16);
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R5G6B5_UNORM_PACK16);
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B5G6R5_UNORM_PACK16);
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R5G5B5A1_UNORM_PACK16);
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B5G5R5A1_UNORM_PACK16);
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_A1R5G5B5_UNORM_PACK16);
|
||||
case VK_FORMAT_R4G4_UNORM_PACK8: GROUP(COLOR, 1, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R4G4_UNORM_PACK8);
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R4G4B4A4_UNORM_PACK16);
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B4G4R4A4_UNORM_PACK16);
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R5G6B5_UNORM_PACK16);
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B5G6R5_UNORM_PACK16);
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R5G5B5A1_UNORM_PACK16);
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B5G5R5A1_UNORM_PACK16);
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_A1R5G5B5_UNORM_PACK16);
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
case VK_FORMAT_R8_SNORM:
|
||||
case VK_FORMAT_R8_USCALED:
|
||||
@@ -83,7 +102,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R8_UINT:
|
||||
case VK_FORMAT_R8_SINT:
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
GROUP(1, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8_SRGB,
|
||||
GROUP(COLOR, 1, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8_SRGB,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R8_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R8_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R8_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R8_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R8_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R8_SINT);
|
||||
@@ -94,7 +113,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R8G8_UINT:
|
||||
case VK_FORMAT_R8G8_SINT:
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
GROUP(2, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8G8_SRGB,
|
||||
GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8G8_SRGB,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R8G8_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R8G8_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R8G8_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R8G8_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R8G8_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R8G8_SINT);
|
||||
@@ -105,7 +124,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R8G8B8_UINT:
|
||||
case VK_FORMAT_R8G8B8_SINT:
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
GROUP(3, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8G8B8_SRGB,
|
||||
GROUP(COLOR, 3, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8G8B8_SRGB,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R8G8B8_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R8G8B8_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R8G8B8_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R8G8B8_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R8G8B8_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R8G8B8_SINT);
|
||||
@@ -116,7 +135,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_B8G8R8_UINT:
|
||||
case VK_FORMAT_B8G8R8_SINT:
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
GROUP(3, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_B8G8R8_SRGB,
|
||||
GROUP(COLOR, 3, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_B8G8R8_SRGB,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B8G8R8_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_B8G8R8_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_B8G8R8_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_B8G8R8_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_B8G8R8_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_B8G8R8_SINT);
|
||||
@@ -127,7 +146,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R8G8B8A8_UINT:
|
||||
case VK_FORMAT_R8G8B8A8_SINT:
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
GROUP(4, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8G8B8A8_SRGB,
|
||||
GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_R8G8B8A8_SRGB,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R8G8B8A8_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R8G8B8A8_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R8G8B8A8_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R8G8B8A8_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R8G8B8A8_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R8G8B8A8_SINT);
|
||||
@@ -138,7 +157,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_B8G8R8A8_UINT:
|
||||
case VK_FORMAT_B8G8R8A8_SINT:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
GROUP(4, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_B8G8R8A8_SRGB,
|
||||
GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_B8G8R8A8_SRGB,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_B8G8R8A8_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_B8G8R8A8_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_B8G8R8A8_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_B8G8R8A8_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_B8G8R8A8_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_B8G8R8A8_SINT);
|
||||
@@ -149,7 +168,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||
GROUP(4, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_A8B8G8R8_SRGB_PACK32,
|
||||
GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_SRGB] = VK_FORMAT_A8B8G8R8_SRGB_PACK32,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_A8B8G8R8_UNORM_PACK32, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_A8B8G8R8_SNORM_PACK32,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_A8B8G8R8_USCALED_PACK32, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_A8B8G8R8_UINT_PACK32, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_A8B8G8R8_SINT_PACK32);
|
||||
@@ -159,7 +178,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_UINT_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_SINT_PACK32:
|
||||
GROUP(4,
|
||||
GROUP(COLOR, 4,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_A2R10G10B10_UNORM_PACK32, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_A2R10G10B10_SNORM_PACK32,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_A2R10G10B10_USCALED_PACK32, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_A2R10G10B10_UINT_PACK32, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_A2R10G10B10_SINT_PACK32);
|
||||
@@ -169,7 +188,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_SINT_PACK32:
|
||||
GROUP(4,
|
||||
GROUP(COLOR, 4,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_A2B10G10R10_UNORM_PACK32, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_A2B10G10R10_SNORM_PACK32,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_A2B10G10R10_USCALED_PACK32, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_A2B10G10R10_UINT_PACK32, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_A2B10G10R10_SINT_PACK32);
|
||||
@@ -180,7 +199,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R16_UINT:
|
||||
case VK_FORMAT_R16_SINT:
|
||||
case VK_FORMAT_R16_SFLOAT:
|
||||
GROUP(2, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16_SFLOAT,
|
||||
GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R16_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R16_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R16_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R16_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R16_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R16_SINT);
|
||||
@@ -191,7 +210,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R16G16_UINT:
|
||||
case VK_FORMAT_R16G16_SINT:
|
||||
case VK_FORMAT_R16G16_SFLOAT:
|
||||
GROUP(4, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16G16_SFLOAT,
|
||||
GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16G16_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R16G16_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R16G16_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R16G16_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R16G16_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R16G16_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R16G16_SINT);
|
||||
@@ -202,7 +221,7 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R16G16B16_UINT:
|
||||
case VK_FORMAT_R16G16B16_SINT:
|
||||
case VK_FORMAT_R16G16B16_SFLOAT:
|
||||
GROUP(6, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16G16B16_SFLOAT,
|
||||
GROUP(COLOR, 6, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16G16B16_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R16G16B16_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R16G16B16_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R16G16B16_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R16G16B16_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R16G16B16_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R16G16B16_SINT);
|
||||
@@ -213,62 +232,66 @@ FormatGroup VKUtil_GetFormatGroup(VkFormat format) {
|
||||
case VK_FORMAT_R16G16B16A16_UINT:
|
||||
case VK_FORMAT_R16G16B16A16_SINT:
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
GROUP(8, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
GROUP(COLOR, 8, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R16G16B16A16_UNORM, .aliases[FORMAT_ALIAS_SNORM] = VK_FORMAT_R16G16B16A16_SNORM,
|
||||
.aliases[FORMAT_ALIAS_USCALED] = VK_FORMAT_R16G16B16A16_USCALED, .aliases[FORMAT_ALIAS_SSCALED] = VK_FORMAT_R16G16B16A16_SSCALED,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R16G16B16A16_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R16G16B16A16_SINT);
|
||||
case VK_FORMAT_R32_UINT:
|
||||
case VK_FORMAT_R32_SINT:
|
||||
case VK_FORMAT_R32_SFLOAT:
|
||||
GROUP(4, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32_SFLOAT,
|
||||
GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R32_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R32_SINT);
|
||||
case VK_FORMAT_R32G32_UINT:
|
||||
case VK_FORMAT_R32G32_SINT:
|
||||
case VK_FORMAT_R32G32_SFLOAT:
|
||||
GROUP(8, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32G32_SFLOAT,
|
||||
GROUP(COLOR, 8, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32G32_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R32G32_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R32G32_SINT);
|
||||
case VK_FORMAT_R32G32B32_UINT:
|
||||
case VK_FORMAT_R32G32B32_SINT:
|
||||
case VK_FORMAT_R32G32B32_SFLOAT:
|
||||
GROUP(12, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
GROUP(COLOR, 12, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R32G32B32_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R32G32B32_SINT);
|
||||
case VK_FORMAT_R32G32B32A32_UINT:
|
||||
case VK_FORMAT_R32G32B32A32_SINT:
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT:
|
||||
GROUP(16, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
GROUP(COLOR, 16, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R32G32B32A32_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R32G32B32A32_SINT);
|
||||
case VK_FORMAT_R64_UINT:
|
||||
case VK_FORMAT_R64_SINT:
|
||||
case VK_FORMAT_R64_SFLOAT:
|
||||
GROUP(8, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64_SFLOAT,
|
||||
GROUP(COLOR, 8, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R64_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R64_SINT);
|
||||
case VK_FORMAT_R64G64_UINT:
|
||||
case VK_FORMAT_R64G64_SINT:
|
||||
case VK_FORMAT_R64G64_SFLOAT:
|
||||
GROUP(16, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64G64_SFLOAT,
|
||||
GROUP(COLOR, 16, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64G64_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R64G64_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R64G64_SINT);
|
||||
case VK_FORMAT_R64G64B64_UINT:
|
||||
case VK_FORMAT_R64G64B64_SINT:
|
||||
case VK_FORMAT_R64G64B64_SFLOAT:
|
||||
GROUP(24, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64G64B64_SFLOAT,
|
||||
GROUP(COLOR, 24, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64G64B64_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R64G64B64_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R64G64B64_SINT);
|
||||
case VK_FORMAT_R64G64B64A64_UINT:
|
||||
case VK_FORMAT_R64G64B64A64_SINT:
|
||||
case VK_FORMAT_R64G64B64A64_SFLOAT:
|
||||
GROUP(32, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64G64B64A64_SFLOAT,
|
||||
GROUP(COLOR, 32, .aliases[FORMAT_ALIAS_SFLOAT] = VK_FORMAT_R64G64B64A64_SFLOAT,
|
||||
.aliases[FORMAT_ALIAS_UINT] = VK_FORMAT_R64G64B64A64_UINT, .aliases[FORMAT_ALIAS_SINT] = VK_FORMAT_R64G64B64A64_SINT);
|
||||
case VK_FORMAT_R10X6_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R10X6_UNORM_PACK16);
|
||||
case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: GROUP(4, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R10X6G10X6_UNORM_2PACK16);
|
||||
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: GROUP(8, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16);
|
||||
case VK_FORMAT_R12X4_UNORM_PACK16: GROUP(2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R12X4_UNORM_PACK16);
|
||||
case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: GROUP(4, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R12X4G12X4_UNORM_2PACK16);
|
||||
case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: GROUP(8, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16);
|
||||
default: GROUP(0);
|
||||
case VK_FORMAT_R10X6_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R10X6_UNORM_PACK16);
|
||||
case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R10X6G10X6_UNORM_2PACK16);
|
||||
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: GROUP(COLOR, 8, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16);
|
||||
case VK_FORMAT_R12X4_UNORM_PACK16: GROUP(COLOR, 2, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R12X4_UNORM_PACK16);
|
||||
case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: GROUP(COLOR, 4, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R12X4G12X4_UNORM_2PACK16);
|
||||
case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: GROUP(COLOR, 8, .aliases[FORMAT_ALIAS_UNORM] = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16);
|
||||
case VK_FORMAT_S8_UINT: GROUP(STENCIL, 1);
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT: GROUP(STENCIL, 3);
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT: GROUP(STENCIL, 4);
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT: GROUP(STENCIL, 5);
|
||||
default: return (FormatGroup) { .bytes = 0, .aspect = (VkImageAspectFlagBits) 0, .aliases[FORMAT_ALIAS_ORIGINAL] = format };
|
||||
}
|
||||
#undef GROUP
|
||||
}
|
||||
|
||||
void VKUtil_LogResultError(const char* string, VkResult result) {
|
||||
JNIEXPORT void VKUtil_LogResultError(const char* string, VkResult result) {
|
||||
const char* r;
|
||||
switch (result) {
|
||||
#define RESULT(T) case T: r = #T; break
|
||||
@@ -311,3 +334,24 @@ void VKUtil_LogResultError(const char* string, VkResult result) {
|
||||
}
|
||||
J2dRlsTraceLn1(J2D_TRACE_ERROR, string, r)
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate src transform to dst
|
||||
* [d00 d01 d02] [s00 s01 s02] [d00s00+d01s10 d00s01+d01s11 d00s02+d01s12+d02]
|
||||
* [d10 d11 d12] [s10 s11 s12] = [d10s11+d11s10 d10s01+d11s11 d10s02+d11s12+d12]
|
||||
* [ 0 0 1 ] [ 0 0 1 ] [ 0 0 1 ]
|
||||
*/
|
||||
void VKUtil_ConcatenateTransform(VKTransform* dst, const VKTransform* src) {
|
||||
float s00 = src->m00, s01 = src->m01, s02 = src->m02;
|
||||
float s10 = src->m10, s11 = src->m11, s12 = src->m12;
|
||||
float d00 = dst->m00, d01 = dst->m01, d02 = dst->m02;
|
||||
float d10 = dst->m10, d11 = dst->m11, d12 = dst->m12;
|
||||
|
||||
dst->m00 = d00 * s00 + d01 * s10;
|
||||
dst->m01 = d00 * s01 + d01 * s11;
|
||||
dst->m02 = d00 * s02 + d01 * s12 + d02;
|
||||
|
||||
dst->m10 = d10 * s00 + d11 * s10;
|
||||
dst->m11 = d10 * s01 + d11 * s11;
|
||||
dst->m12 = d10 * s02 + d11 * s12 + d12;
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
#ifndef VKUtil_h_Included
|
||||
#define VKUtil_h_Included
|
||||
#include <stdlib.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <Trace.h>
|
||||
#include "awt.h"
|
||||
#include "jni_util.h"
|
||||
@@ -43,7 +42,7 @@
|
||||
#endif
|
||||
|
||||
// Useful logging & result checking macros
|
||||
void VKUtil_LogResultError(const char* string, VkResult result);
|
||||
JNIEXPORT void VKUtil_LogResultError(const char* string, VkResult result);
|
||||
inline VkBool32 VKUtil_CheckError(VkResult result, const char* errorMessage) {
|
||||
if (result != VK_SUCCESS) {
|
||||
VKUtil_LogResultError(errorMessage, result);
|
||||
@@ -69,6 +68,19 @@ inline VkBool32 VKUtil_CheckError(VkResult result, const char* errorMessage) {
|
||||
#define C_ARRAY_UTIL_ALLOCATION_FAILED() VK_FATAL_ERROR("CArrayUtil allocation failed")
|
||||
#include "CArrayUtil.h"
|
||||
|
||||
#define VK_ID_TRANSFORM ((VKTransform)\
|
||||
{1.0f, 0.0f, 0.0f, \
|
||||
0.0f, 1.0f, 0.0f})
|
||||
// 0.0f, 0.0f, 1.0f -- omitted values
|
||||
|
||||
#define VK_IS_NEQ_TRANSFORM(PA, PB) \
|
||||
((PA)->m00 != (PB)->m00 || \
|
||||
(PA)->m01 != (PB)->m01 || \
|
||||
(PA)->m02 != (PB)->m02 || \
|
||||
(PA)->m10 != (PB)->m10 || \
|
||||
(PA)->m11 != (PB)->m11 || \
|
||||
(PA)->m12 != (PB)->m12 )
|
||||
|
||||
typedef enum {
|
||||
FORMAT_ALIAS_ORIGINAL = 0,
|
||||
FORMAT_ALIAS_UNORM = 1,
|
||||
@@ -82,14 +94,27 @@ typedef enum {
|
||||
FORMAT_ALIAS_COUNT = 9
|
||||
} FormatAlias;
|
||||
|
||||
#define VK_PACK_SWIZZLE(R, G, B, A) ((VKPackedSwizzle)(R) & 0b111) | (((VKPackedSwizzle)(G) & 0b111) << 3) | \
|
||||
(((VKPackedSwizzle)(B) & 0b111) << 6) | (((VKPackedSwizzle)(A) & 0b111) << 9)
|
||||
|
||||
#define VK_UNPACK_SWIZZLE(S) ((VkComponentMapping){ (VKPackedSwizzle)(S) & 0b111, ((VKPackedSwizzle)(S) >> 3) & 0b111, \
|
||||
((VKPackedSwizzle)(S) >> 6) & 0b111, ((VKPackedSwizzle)(S) >> 9) & 0b111 })
|
||||
|
||||
/**
|
||||
* Group of format aliases. Use FormatAlias enum values to index into FormatGroup.aliases.
|
||||
*/
|
||||
typedef struct {
|
||||
VkFormat aliases[FORMAT_ALIAS_COUNT];
|
||||
uint bytes;
|
||||
VkFormat aliases[FORMAT_ALIAS_COUNT];
|
||||
uint bytes;
|
||||
VkImageAspectFlagBits aspect;
|
||||
} FormatGroup;
|
||||
|
||||
typedef struct {
|
||||
uint32_t barrierCount;
|
||||
VkPipelineStageFlags srcStages;
|
||||
VkPipelineStageFlags dstStages;
|
||||
} VKBarrierBatch;
|
||||
|
||||
/**
|
||||
* Vulkan expects linear colors.
|
||||
* However Java2D expects legacy behavior, as if colors were blended in sRGB color space.
|
||||
@@ -101,7 +126,12 @@ typedef struct {
|
||||
* Note: we receive colors from Java with straight (non-premultiplied) alpha, which is done to prevent precision loss.
|
||||
* This is controlled by PixelConverter parameter of SurfaceType, see VKSurfaceData.java.
|
||||
*/
|
||||
Color VKUtil_DecodeJavaColor(uint32_t color);
|
||||
Color VKUtil_DecodeJavaColor(uint32_t color, AlphaType alphaType);
|
||||
|
||||
/**
|
||||
* Get floating-point RGBA color components with specified AlphaType.
|
||||
*/
|
||||
RGBA VKUtil_GetRGBA(Color color, AlphaType alphaType);
|
||||
|
||||
/**
|
||||
* Integer log2, the same as index of highest set bit.
|
||||
@@ -113,6 +143,11 @@ uint32_t VKUtil_Log2(uint64_t i);
|
||||
*/
|
||||
FormatGroup VKUtil_GetFormatGroup(VkFormat format);
|
||||
|
||||
/**
|
||||
* Apply src transform to dst
|
||||
*/
|
||||
void VKUtil_ConcatenateTransform(VKTransform* dst, const VKTransform* src);
|
||||
|
||||
/*
|
||||
* The following macros allow the caller to return (or continue) if the
|
||||
* provided value is NULL. (The strange else clause is included below to
|
||||
|
||||
@@ -24,101 +24,79 @@
|
||||
*/
|
||||
package sun.awt.wl;
|
||||
|
||||
import jdk.internal.misc.InnocuousThread;
|
||||
import sun.awt.datatransfer.DataTransferer;
|
||||
import sun.awt.datatransfer.SunClipboard;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.FlavorTable;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.SortedMap;
|
||||
|
||||
public final class WLClipboard extends SunClipboard {
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.wl.WLClipboard");
|
||||
|
||||
public static final int INITIAL_MIME_FORMATS_COUNT = 10;
|
||||
private static final int DEFAULT_BUFFER_SIZE = 4096;
|
||||
private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
|
||||
private static final String plainTextUtf8 = "text/plain;charset=utf-8";
|
||||
private static final String utf8String = "UTF8_STRING";
|
||||
|
||||
// A native handle of a Wayland queue dedicated to handling
|
||||
// data offer-related events
|
||||
private static final long dataOfferQueuePtr;
|
||||
|
||||
private final long ID;
|
||||
private final WLDataDevice dataDevice;
|
||||
|
||||
// true if this is the "primary selection" clipboard,
|
||||
// false otherwise (the regular clipboard).
|
||||
private final boolean isPrimary; // used by native
|
||||
private final boolean isPrimary;
|
||||
|
||||
private final Object dataLock = new Object();
|
||||
// A handle to the native clipboard representation, 0 if not available.
|
||||
private long clipboardNativePtr; // guarded by dataLock
|
||||
private long ourOfferNativePtr; // guarded by dataLock
|
||||
|
||||
// The list of numeric format IDs the current clipboard is available in;
|
||||
// could be null or empty.
|
||||
private List<Long> clipboardFormats; // guarded by dataLock
|
||||
// Latest active data offer to us, containing up-to-date clipboard content,
|
||||
// as provided by the Wayland compositor.
|
||||
// If null, there's no clipboard data available.
|
||||
// Guarded by dataLock.
|
||||
private WLDataOffer clipboardDataOfferedToUs;
|
||||
|
||||
// The "current" list formats for the new clipboard contents that is about
|
||||
// to be received from Wayland. Could be empty, but never null.
|
||||
private List<Long> newClipboardFormats = new ArrayList<>(INITIAL_MIME_FORMATS_COUNT); // guarded by dataLock
|
||||
// Clipboard data source we are providing to the Wayland compositor.
|
||||
// If null, we are not offering any clipboard data at the moment.
|
||||
// Guarded by dataLock.
|
||||
private WLDataSource ourDataSource;
|
||||
|
||||
private static final Thread clipboardDispatcherThread;
|
||||
static {
|
||||
initIDs();
|
||||
dataOfferQueuePtr = createDataOfferQueue();
|
||||
flavorTable = DataTransferer.adaptFlavorMap(getDefaultFlavorTable());
|
||||
|
||||
Thread t = InnocuousThread.newThread(
|
||||
"AWT-Wayland-clipboard-dispatcher",
|
||||
WLClipboard::dispatchDataOfferQueue);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
clipboardDispatcherThread = t;
|
||||
}
|
||||
|
||||
private final static FlavorTable flavorTable;
|
||||
|
||||
public WLClipboard(String name, boolean isPrimary) {
|
||||
public WLClipboard(WLDataDevice dataDevice, String name, boolean isPrimary) {
|
||||
super(name);
|
||||
this.ID = initNative(isPrimary);
|
||||
this.isPrimary = isPrimary;
|
||||
this.dataDevice = dataDevice;
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: Created " + this);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dispatchDataOfferQueue() {
|
||||
dispatchDataOfferQueueImpl(dataOfferQueuePtr); // does not return until error or server disconnect
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: data offer dispatcher exited");
|
||||
private int getProtocol() {
|
||||
if (isPrimary) {
|
||||
return WLDataDevice.DATA_TRANSFER_PROTOCOL_PRIMARY_SELECTION;
|
||||
} else {
|
||||
return WLDataDevice.DATA_TRANSFER_PROTOCOL_WAYLAND;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Clipboard: Wayland %s (%x)", (isPrimary ? "selection clipboard" : "clipboard"), ID);
|
||||
return String.format("Clipboard: Wayland %s", (isPrimary ? "selection clipboard" : "clipboard"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getID() {
|
||||
return ID;
|
||||
return isPrimary ? 2 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we loose ownership of the clipboard.
|
||||
* Called when we lose ownership of the clipboard.
|
||||
*/
|
||||
@Override
|
||||
protected void clearNativeContext() {
|
||||
@@ -164,34 +142,20 @@ public final class WLClipboard extends SunClipboard {
|
||||
notifyOfNewFormats(formats);
|
||||
|
||||
if (formats.length > 0) {
|
||||
String[] mime = new String[formats.length];
|
||||
for (int i = 0; i < formats.length; i++) {
|
||||
mime[i] = wlDataTransferer.getNativeForFormat(formats[i]);
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: formats mapping " + formats[i] + " -> " + mime[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: Offering new contents (" + contents + ") in these MIME formats: " + Arrays.toString(mime));
|
||||
log.fine("Clipboard: Offering new contents (" + contents + ")");
|
||||
}
|
||||
|
||||
WLDataSource newOffer = null;
|
||||
newOffer = new WLDataSource(dataDevice, getProtocol(), contents);
|
||||
|
||||
synchronized (dataLock) {
|
||||
if (ourOfferNativePtr != 0) {
|
||||
cancelOffer(ourOfferNativePtr);
|
||||
ourOfferNativePtr = 0;
|
||||
if (ourDataSource != null) {
|
||||
ourDataSource.destroy();
|
||||
}
|
||||
ourDataSource = newOffer;
|
||||
dataDevice.setSelection(getProtocol(), newOffer, eventSerial);
|
||||
}
|
||||
long newOfferPtr = offerData(eventSerial, mime, contents, dataOfferQueuePtr);
|
||||
synchronized (dataLock) {
|
||||
ourOfferNativePtr = newOfferPtr;
|
||||
}
|
||||
|
||||
// Once we have offered the data, someone may come back and ask to provide them.
|
||||
// In that event, the transferContentsWithType() will be called from native on the
|
||||
// clipboard dispatch thread.
|
||||
// A reference to contents is retained until we are notified of the new contents
|
||||
// by the Wayland server.
|
||||
}
|
||||
} else {
|
||||
this.owner = null;
|
||||
@@ -200,74 +164,32 @@ public final class WLClipboard extends SunClipboard {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native on EDT when a client has asked to provide the actual data for
|
||||
* the clipboard that we own in the given format to the given file.
|
||||
* NB: that client could be us, but we aren't necessarily aware of that once we
|
||||
* lost keyboard focus at least once after Ctrl-C.
|
||||
* Returns zero-length array (not null) if the number of available formats is zero.
|
||||
*
|
||||
* @param contents a reference to the clipboard's contents to be transferred
|
||||
* @param mime transfer the contents in this MIME format
|
||||
* @param destFD transfer the contents to this file descriptor and close it afterward
|
||||
*
|
||||
* @throws IOException in case writing to the given file descriptor failed
|
||||
*/
|
||||
private void transferContentsWithType(Transferable contents, String mime, int destFD) throws IOException {
|
||||
assert (Thread.currentThread() == clipboardDispatcherThread);
|
||||
|
||||
Objects.requireNonNull(contents);
|
||||
Objects.requireNonNull(mime);
|
||||
|
||||
WLDataTransferer wlDataTransferer = (WLDataTransferer) DataTransferer.getInstance();
|
||||
SortedMap<Long,DataFlavor> formatMap =
|
||||
wlDataTransferer.getFormatsForTransferable(contents, flavorTable);
|
||||
|
||||
long targetFormat = wlDataTransferer.getFormatForNativeAsLong(mime);
|
||||
DataFlavor flavor = formatMap.get(targetFormat);
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: will write contents (" + contents + ") in format " + mime + " to fd=" + destFD);
|
||||
log.fine("Clipboard: data flavor: " + flavor);
|
||||
}
|
||||
|
||||
if (flavor != null) {
|
||||
byte[] bytes = wlDataTransferer.translateTransferable(contents, flavor, targetFormat);
|
||||
if (bytes == null) return;
|
||||
FileDescriptor javaDestFD = new FileDescriptor();
|
||||
jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess().set(javaDestFD, destFD);
|
||||
try (var out = new FileOutputStream(javaDestFD)) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: about to write " + bytes.length + " bytes to " + out);
|
||||
}
|
||||
|
||||
FileChannel ch = out.getChannel();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
// Need to write with retries because when a pipe is in the non-blocking mode
|
||||
// writing more than its capacity (usually 16 pages or 64K) fails with EAGAIN.
|
||||
// Since we receive destFD from the Wayland sever, we can't assume it
|
||||
// to always be in the blocking mode.
|
||||
while (buffer.hasRemaining()) {
|
||||
ch.write(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return formats the current clipboard is available in; could be null
|
||||
* @throws IllegalStateException if formats could not be retrieved
|
||||
*/
|
||||
@Override
|
||||
protected long[] getClipboardFormats() {
|
||||
WLDataTransferer wlDataTransferer = (WLDataTransferer) DataTransferer.getInstance();
|
||||
List<String> mimes;
|
||||
synchronized (dataLock) {
|
||||
if (clipboardFormats != null && !clipboardFormats.isEmpty()) {
|
||||
long[] res = new long[clipboardFormats.size()];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = clipboardFormats.get(i);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return null;
|
||||
if (clipboardDataOfferedToUs == null) {
|
||||
return new long[0];
|
||||
}
|
||||
|
||||
mimes = clipboardDataOfferedToUs.getMimes();
|
||||
}
|
||||
|
||||
var formatsSet = new HashSet<Long>();
|
||||
for (var mime : mimes) {
|
||||
formatsSet.add(wlDataTransferer.getFormatForNativeAsLong(mime));
|
||||
if (mime.equalsIgnoreCase(plainTextUtf8)) {
|
||||
// some compositors (WSLg) don't advertise UTF8_STRING
|
||||
formatsSet.add(wlDataTransferer.getFormatForNativeAsLong(utf8String));
|
||||
}
|
||||
}
|
||||
|
||||
return formatsSet.stream().mapToLong(Long::longValue).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,101 +201,21 @@ public final class WLClipboard extends SunClipboard {
|
||||
*/
|
||||
@Override
|
||||
protected byte[] getClipboardData(long format) throws IOException {
|
||||
int fd = getClipboardFDIn(format);
|
||||
if (fd >= 0) {
|
||||
FileDescriptor javaFD = new FileDescriptor();
|
||||
jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess().set(javaFD, fd);
|
||||
try (var in = new FileInputStream(javaFD)) {
|
||||
byte[] bytes = readAllBytesFrom(in);
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: read data from " + fd + ": "
|
||||
+ (bytes != null ? bytes.length : 0) + " bytes");
|
||||
final WLDataTransferer wlDataTransferer = (WLDataTransferer) DataTransferer.getInstance();
|
||||
final long utf8StringFormat = wlDataTransferer.getFormatForNativeAsLong(utf8String);
|
||||
synchronized (dataLock) {
|
||||
// Iterate over all mime types, since the mapping between mime types and java formats might not be 1:1
|
||||
// Also treat text/plain;charset=utf-8 as UTF8_STRING
|
||||
for (var mime : clipboardDataOfferedToUs.getMimes()) {
|
||||
long curFormat = wlDataTransferer.getFormatForNativeAsLong(mime);
|
||||
if (curFormat == format) {
|
||||
return clipboardDataOfferedToUs.receiveData(mime);
|
||||
} else if (mime.equalsIgnoreCase(plainTextUtf8) && utf8StringFormat == format) {
|
||||
return clipboardDataOfferedToUs.receiveData(mime);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getClipboardFDIn(long format) {
|
||||
synchronized (dataLock) {
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: requested content of clipboard with handle "
|
||||
+ clipboardNativePtr + " in format " + format);
|
||||
}
|
||||
if (clipboardNativePtr != 0) {
|
||||
WLDataTransferer wlDataTransferer = (WLDataTransferer) DataTransferer.getInstance();
|
||||
String mime = wlDataTransferer.getNativeForFormat(format);
|
||||
int fd = requestDataInFormat(clipboardNativePtr, mime);
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: will read data from " + fd + " in format " + mime);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native to notify us of the availability of a new clipboard
|
||||
* denoted by the native handle in a specific MIME format.
|
||||
* This method is usually called repeatedly with the same nativePtr and
|
||||
* different formats. When all formats are announces in this way,
|
||||
* handleNewClipboard() is called.
|
||||
*
|
||||
* @param nativePtr a native handle to the clipboard
|
||||
* @param mime the MIME format in which this clipboard is available.
|
||||
*/
|
||||
private void handleClipboardFormat(long nativePtr, String mime) {
|
||||
WLDataTransferer wlDataTransferer = (WLDataTransferer) DataTransferer.getInstance();
|
||||
Long format = wlDataTransferer.getFormatForNativeAsLong(mime);
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: new format is available for " + nativePtr + ": " + mime);
|
||||
}
|
||||
|
||||
synchronized (dataLock) {
|
||||
newClipboardFormats.add(format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native to notify us that a new clipboard content
|
||||
* has been made available. The list of supported formats
|
||||
* should have already been received and saved in newClipboardFormats.
|
||||
*
|
||||
* @param newClipboardNativePtr a native handle to the clipboard
|
||||
*/
|
||||
private void handleNewClipboard(long newClipboardNativePtr) {
|
||||
// Since we have a new clipboard, the existing one is no longer valid.
|
||||
// We have no way of knowing whether this "new" one is the same as the "old" one.
|
||||
lostOwnershipNow(null);
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("Clipboard: new clipboard is available: " + newClipboardNativePtr);
|
||||
}
|
||||
|
||||
synchronized (dataLock) {
|
||||
long oldClipboardNativePtr = clipboardNativePtr;
|
||||
if (oldClipboardNativePtr != 0) {
|
||||
// "The client must destroy the previous selection data_offer, if any, upon receiving this event."
|
||||
destroyClipboard(oldClipboardNativePtr);
|
||||
}
|
||||
clipboardFormats = newClipboardFormats;
|
||||
clipboardNativePtr = newClipboardNativePtr; // Could be NULL
|
||||
|
||||
newClipboardFormats = new ArrayList<>(INITIAL_MIME_FORMATS_COUNT);
|
||||
}
|
||||
|
||||
notifyOfNewFormats(getClipboardFormats());
|
||||
}
|
||||
|
||||
private void handleOfferCancelled(long offerNativePtr) {
|
||||
synchronized (dataLock) {
|
||||
assert offerNativePtr == ourOfferNativePtr;
|
||||
ourOfferNativePtr = 0;
|
||||
}
|
||||
throw new IOException("No appropriate mime type found for WLClipboard.getClipboardData with format = " + format);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -397,76 +239,14 @@ public final class WLClipboard extends SunClipboard {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given input stream until EOF and returns its contents as an array of bytes.
|
||||
*/
|
||||
private byte[] readAllBytesFrom(FileInputStream inputStream) throws IOException {
|
||||
int len = Integer.MAX_VALUE;
|
||||
List<byte[]> bufs = null;
|
||||
byte[] result = null;
|
||||
int total = 0;
|
||||
int remaining = len;
|
||||
int n;
|
||||
do {
|
||||
byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)];
|
||||
int nread = 0;
|
||||
void handleClipboardOffer(WLDataOffer offer /* nullable */) {
|
||||
lostOwnershipNow(null);
|
||||
|
||||
while ((n = inputStream.read(buf, nread,
|
||||
Math.min(buf.length - nread, remaining))) > 0) {
|
||||
nread += n;
|
||||
remaining -= n;
|
||||
synchronized (dataLock) {
|
||||
if (clipboardDataOfferedToUs != null) {
|
||||
clipboardDataOfferedToUs.destroy();
|
||||
}
|
||||
|
||||
if (nread > 0) {
|
||||
if (MAX_BUFFER_SIZE - total < nread) {
|
||||
throw new OutOfMemoryError("Required array size too large");
|
||||
}
|
||||
if (nread < buf.length) {
|
||||
buf = Arrays.copyOfRange(buf, 0, nread);
|
||||
}
|
||||
total += nread;
|
||||
if (result == null) {
|
||||
result = buf;
|
||||
} else {
|
||||
if (bufs == null) {
|
||||
bufs = new ArrayList<>();
|
||||
bufs.add(result);
|
||||
}
|
||||
bufs.add(buf);
|
||||
}
|
||||
}
|
||||
// if the last call to read returned -1 or the number of bytes
|
||||
// requested have been read then break
|
||||
} while (n >= 0 && remaining > 0);
|
||||
|
||||
if (bufs == null) {
|
||||
if (result == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return result.length == total ?
|
||||
result : Arrays.copyOf(result, total);
|
||||
clipboardDataOfferedToUs = offer;
|
||||
}
|
||||
|
||||
result = new byte[total];
|
||||
int offset = 0;
|
||||
remaining = total;
|
||||
for (byte[] b : bufs) {
|
||||
int count = Math.min(b.length, remaining);
|
||||
System.arraycopy(b, 0, result, offset, count);
|
||||
offset += count;
|
||||
remaining -= count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
private static native long createDataOfferQueue();
|
||||
private static native void dispatchDataOfferQueueImpl(long dataOfferQueuePtr);
|
||||
private native long initNative(boolean isPrimary);
|
||||
private native long offerData(long eventSerial, String[] mime, Object data, long dataOfferQueuePtr);
|
||||
private native void cancelOffer(long offerNativePtr);
|
||||
|
||||
private native int requestDataInFormat(long clipboardNativePtr, String mime);
|
||||
private native void destroyClipboard(long clipboardNativePtr);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user