From 3dbefcdafbf1ea9b5df4efcfd6e4e990fce84968 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sat, 7 May 2022 13:22:50 +0930 Subject: [PATCH] Add abstracted display module. SDF demo work in progress. Netbeans re-formatting. Netbeans project files. --- .gitignore | 4 + Makefile | 7 +- nbproject/build-impl.xml | 1866 +++++++++++++++++ nbproject/genfiles.properties | 8 + nbproject/project.properties | 94 + nbproject/project.xml | 16 + .../classes/au/notzed/display/Display.java | 43 + .../classes/au/notzed/display/Event.java | 45 + .../classes/au/notzed/display/Window.java | 130 ++ src/notzed.display/classes/module-info.java | 8 + .../classes/module-info.java | 4 +- .../classes/vulkan/test/TestCube.java | 212 +- .../classes/vulkan/test/TestMandelbrot.java | 106 +- .../classes/vulkan/test/TestSDF.java | 1056 ++++++++++ src/notzed.vulkan.test/gen/gen.make | 25 + src/notzed.vulkan.test/gen/generate-shaderio | 46 + src/notzed.vulkan.test/gen/sdf.frag | 21 + src/notzed.vulkan.test/gen/sdf.vert | 9 + src/notzed.vulkan/gen/generate-vulkan | 169 +- src/notzed.vulkan/gen/struct-types.api | 36 +- src/notzed.vulkan/gen/vulkan.pm | 22 +- src/notzed.xlib/gen/xlib.api | 14 + 22 files changed, 3688 insertions(+), 253 deletions(-) create mode 100644 nbproject/build-impl.xml create mode 100644 nbproject/genfiles.properties create mode 100644 nbproject/project.properties create mode 100644 nbproject/project.xml create mode 100644 src/notzed.display/classes/au/notzed/display/Display.java create mode 100644 src/notzed.display/classes/au/notzed/display/Event.java create mode 100644 src/notzed.display/classes/au/notzed/display/Window.java create mode 100644 src/notzed.display/classes/module-info.java create mode 100644 src/notzed.vulkan.test/classes/vulkan/test/TestSDF.java create mode 100755 src/notzed.vulkan.test/gen/generate-shaderio create mode 100644 src/notzed.vulkan.test/gen/sdf.frag create mode 100644 src/notzed.vulkan.test/gen/sdf.vert diff --git a/.gitignore b/.gitignore index 58686c2..45e0b9a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ bin/ config.make mandelbrot.pam movie.avi +/build/ +/dist/ +/.lib/ +/nbproject/private/ diff --git a/Makefile b/Makefile index c22d81c..5cee474 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ java_MODULES = notzed.nativez \ notzed.apistatic notzed.apiobject \ notzed.ffmpeg \ notzed.clstatic \ - notzed.xlib notzed.xcb \ + notzed.xlib notzed.xcb notzed.display \ notzed.vkregistry notzed.vkregistry.test \ notzed.vkheader notzed.vkheader.test \ notzed.vulkan notzed.vulkan.test @@ -27,6 +27,7 @@ notzed.vulkan_JDEPMOD = notzed.nativez notzed.xlib notzed.xcb notzed.vulkan.test_JDEPMOD = notzed.vulkan notzed.xcb_JDEPMOD = notzed.nativez notzed.xlib_JDEPMOD = notzed.nativez +notzed.display_JDEPMOD = notzed.xlib notzed.xcb notzed.apistatic_JMAIN = api.test.TestAPI notzed.apiobject_JMAIN = api.test.TestAPI @@ -43,3 +44,7 @@ notzed.vkheader.test_JMAINFLAGS = --enable-native-access=notzed.nativez,notzed.x notzed.vulkan.test_JMAINFLAGS = --enable-native-access=notzed.nativez,notzed.xlib,notzed.xcb,notzed.vulkan include java.make + +maven_central_JARS =org.openjdk.jmh:jmh-core:1.33 org.openjdk.jmh:jmh-generator-annprocess:1.33 + +include maven.make diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..99e630a --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1866 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +package netbeans; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; + +public class CoalesceKeyvalue extends Task { + private String property; + + public void setProperty(String property) { + this.property = property; + } + + private String value; + + public void setValue(String value) { + this.value = value; + } + + private String valueSep; + + public void setValueSep(String valueSep) { + this.valueSep = valueSep; + } + + private String entrySep; + + public void setEntrySep(String entrySep) { + this.entrySep = entrySep; + } + + private String multiSep; + + public void setMultiSep(String multiSep) { + this.multiSep = multiSep; + } + + private String outSep; + + public void setOutSep(String outSep) { + this.outSep = outSep; + } + + @Override + public void execute() throws BuildException { + List<String> result = new ArrayList<>(); + Map<String, List<String>> module2Paths = new HashMap<>(); + + for (String entry : value.split(Pattern.quote(entrySep))) { + String[] keyValue = entry.split(Pattern.quote(valueSep), 2); + if (keyValue.length == 1) { + result.add(keyValue[0]); + } else { + module2Paths.computeIfAbsent(keyValue[0], s -> new ArrayList<>()) + .add(keyValue[1].trim()); + } + } + module2Paths.entrySet() + .stream() + .forEach(e -> result.add(e.getKey() + valueSep + e.getValue().stream().collect(Collectors.joining(multiSep)))); + getProject().setProperty(property, result.stream().collect(Collectors.joining(" " + entrySep))); + } + +} + + + + +package netbeans; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; + +public class ModsourceRegexp extends Task { + private String property; + + public void setProperty(String property) { + this.property = property; + } + + private String filePattern; + + public void setFilePattern(String filePattern) { + this.filePattern = filePattern; + } + + private String modsource; + + public void setModsource(String modsource) { + this.modsource = modsource; + } + + private List<String> expandGroup(String grp) { + List<String> exp = new ArrayList<>(); + String item = ""; + int depth = 0; + + for (int i = 0; i < grp.length(); i++) { + char c = grp.charAt(i); + switch (c) { + case '{': + if (depth++ == 0) { + continue; + } + break; + case '}': + if (--depth == 0) { + exp.add(item); + continue; + } + break; + case ',': + if (depth == 1) { + exp.add(item); + item = ""; + continue; + } + default: + break; + } + item = item + c; + } + return exp; + } + + private List<String> pathVariants(String spec) { + return pathVariants(spec, new ArrayList<>()); + } + + private List<String> pathVariants(String spec, List<String> res) { + int start = spec.indexOf('{'); + if (start == -1) { + res.add(spec); + return res; + } + int depth = 1; + int end; + for (end = start + 1; end < spec.length() && depth > 0; end++) { + char c = spec.charAt(end); + switch (c) { + case '{': depth++; break; + case '}': depth--; break; + } + } + String prefix = spec.substring(0, start); + String suffix = spec.substring(end); + expandGroup(spec.substring(start, end)).stream().forEach(item -> { + pathVariants(prefix + item + suffix, res); + }); + return res; + } + + private String toRegexp2(String spec, String filepattern, String separator) { + List<String> prefixes = new ArrayList<>(); + List<String> suffixes = new ArrayList<>(); + pathVariants(spec).forEach(item -> { + suffixes.add(item); + }); + String tail = ""; + String separatorString = separator; + if ("\\".equals(separatorString)) { + separatorString = "\\\\"; + } + if (filepattern != null && !Objects.equals(filepattern, tail)) { + tail = separatorString + filepattern; + } + return "([^" + separatorString +"]+)\\Q" + separator + "\\E(" + suffixes.stream().collect(Collectors.joining("|")) + ")" + tail; + } + + @Override + public void execute() throws BuildException { + getProject().setProperty(property, toRegexp2(modsource, filePattern, getProject().getProperty("file.separator"))); + } + +} + + + + +package netbeans; + +import java.io.File; +import java.util.Arrays; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.selectors.BaseExtendSelector; + +public class ModuleInfoSelector extends BaseExtendSelector { + + @Override + public boolean isSelected(File basedir, String filename, File file) throws BuildException { + String extension = Arrays.stream(getParameters()) + .filter(p -> "extension".equals(p.getName())) + .map(p -> p.getValue()) + .findAny() + .get(); + return !new File(file, "module-info." + extension).exists(); + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @{paths} + + + + + + + + + + + + @{paths} + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set src.gen.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.modules.dir + Must set dist.javadoc.dir + Must set build.test.modules.dir + Must set build.test.results.dir + Must set build.classes.excludes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No main class specified + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..161302e --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=40912c6b +build.xml.script.CRC32=1a338ef5 +build.xml.stylesheet.CRC32=32069288@1.17 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=40912c6b +nbproject/build-impl.xml.script.CRC32=d2abfa69 +nbproject/build-impl.xml.stylesheet.CRC32=d1ebcf0f@1.17 diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..dc576dc --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,94 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=panamaz +application.vendor=notzed +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +build.modules.dir=${build.dir}/modules +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.modules.dir=${build.dir}/test/modules +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.modulepath=\ + ${run.modulepath} +debug.test.classpath=\ + ${run.test.classpath} +debug.test.modulepath=\ + ${run.test.modulepath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.javadoc.dir=${dist.dir}/javadoc +dist.jlink.dir=${dist.dir}/jlink +dist.jlink.output=${dist.jlink.dir}/panamaz +endorsed.classpath= +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.external.vm=false +javac.modulepath= +javac.processormodulepath= +javac.processorpath=\ + ${javac.classpath} +javac.source=18 +javac.target=18 +javac.test.classpath=\ + ${javac.classpath} +javac.test.modulepath=\ + ${javac.modulepath}:\ + ${build.modules.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.html5=false +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +# The jlink additional root modules to resolve +jlink.additionalmodules= +# The jlink additional command line parameters +jlink.additionalparam= +jlink.launcher=true +jlink.launcher.name=panamaz +platform.active=default_platform +run.classpath= +run.jvmargs=--enable-native-access=notzed.vulkan,notzed.nativez,notzed.xlib +run.modulepath=\ + ${javac.modulepath}:\ + ${build.modules.dir} +run.test.classpath=\ + ${javac.test.classpath} +run.test.modulepath=\ + ${javac.test.modulepath}:\ + ${build.test.modules.dir} +source.encoding=UTF-8 +src.dir=src +src.dir.path=classes +src.gen.dir=bin/gen +src.gen.dir.path=classes +test.src.dir=src +test.src.dir.path=tests diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..680ffb4 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2semodule + + + panamaz + + + + + + + + + + diff --git a/src/notzed.display/classes/au/notzed/display/Display.java b/src/notzed.display/classes/au/notzed/display/Display.java new file mode 100644 index 0000000..55806b8 --- /dev/null +++ b/src/notzed.display/classes/au/notzed/display/Display.java @@ -0,0 +1,43 @@ + +package au.notzed.display; + +import jdk.incubator.foreign.*; +import au.notzed.nativez.*; + +import vulkan.*; +import static vulkan.Vulkan.*; + +import xlib.*; +import static xlib.XLib.*; + +public abstract class Display { + + public abstract Window createWindow(int width, int height); + public abstract void close(); + + public static Display createX11Display() { + return new X11Display(XOpenDisplay(null)); + } + + static class X11Display extends Display { + XDisplay display; + + static { + XInitThreads(); + } + + X11Display(XDisplay display) { + this.display = display; + } + + public Window createWindow(int width, int height) { + return Window.createX11Window(display, width, height); + } + + public void close() { + XCloseDisplay(display); + } + } + + // xcb, sdl etc +} diff --git a/src/notzed.display/classes/au/notzed/display/Event.java b/src/notzed.display/classes/au/notzed/display/Event.java new file mode 100644 index 0000000..31af6d5 --- /dev/null +++ b/src/notzed.display/classes/au/notzed/display/Event.java @@ -0,0 +1,45 @@ +package au.notzed.display; + +// basic event handling +public class Event { + + public final int type; + public final int x, y, width, height; + // shift etc + public final int key; + public final int button; + + public static final int CLOSE = 0; + public static final int KEY = 1; + public static final int POINTER = 2; + public static final int BUTTON = 3; + public static final int EXPOSE = 4; + public static final int RESIZE = 5; + + public Event(int type, int x, int y, int width, int height, int key, int button) { + this.type = type; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.key = key; + this.button = button; + } + + public static Event key(int key) { + return new Event(KEY, 0, 0, 0, 0, key, 0); + } + + public static Event expose(int x, int y, int width, int height) { + return new Event(EXPOSE, x, y, width, height, 0, 0); + } + + public static Event resize(int x, int y, int width, int height) { + return new Event(RESIZE, x, y, width, height, 0, 0); + } + + public static Event close() { + return new Event(CLOSE, 0, 0, 0, 0, 0, 0); + } + +} diff --git a/src/notzed.display/classes/au/notzed/display/Window.java b/src/notzed.display/classes/au/notzed/display/Window.java new file mode 100644 index 0000000..74d40c0 --- /dev/null +++ b/src/notzed.display/classes/au/notzed/display/Window.java @@ -0,0 +1,130 @@ +package au.notzed.display; + +import jdk.incubator.foreign.*; +import au.notzed.nativez.*; + +import vulkan.*; +import static vulkan.Vulkan.*; + +import xlib.*; +import static xlib.XLib.*; + +public abstract class Window { + + public abstract VkSurfaceKHR createVulkanSurface(VkInstance instance, ResourceScope scope); + + public abstract Event nextEvent(boolean blocking); + + public abstract void close(); + + static Window createX11Window(XDisplay display, int width, int height) { + try ( Frame frame = Frame.frame()) { + long visualMask = VisualScreenMask; + IntArray numberOfVisuals = IntArray.createArray(1, frame); + XVisualInfo vInfoTemplate = XVisualInfo.create(frame); + + vInfoTemplate.setScreen(DefaultScreen(display)); + + XVisualInfo visualInfo = XGetVisualInfo(display, visualMask, vInfoTemplate, numberOfVisuals); + long colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.getScreen()), visualInfo.getVisual(), AllocNone); + + XSetWindowAttributes windowAttributes = XSetWindowAttributes.create(frame); + + windowAttributes.setColormap(colormap); + windowAttributes.setBackgroundPixel(0xffffffff); + windowAttributes.setBorderPixel(0); + windowAttributes.setEventMask(KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask); + //windowAttributes.setEventMask(0xffffff); + + long window = XCreateWindow(display, RootWindow(display, vInfoTemplate.getScreen()), + 0, 0, width, height, + 0, visualInfo.getDepth(), InputOutput, visualInfo.getVisual(), + CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, windowAttributes); + + XSelectInput(display, window, ExposureMask | KeyPressMask | StructureNotifyMask | PointerMotionMask); + //XSelectInput(display, window, 0xffffff); + XMapWindow(display, window); + XFlush(display); + + return new X11Window(display, window); + } + } + + static class X11Window extends Window { + + XDisplay display; + long window; + // TODO: move to display + long wm_delete_window; + long wm_protocols; + + X11Window(XDisplay display, long window) { + this.display = display; + this.window = window; + wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0); + wm_protocols = XInternAtom(display, "WM_PROTOCOLS", 0); + try ( Frame frame = Frame.frame()) { + LongArray atoms = LongArray.create(frame, wm_delete_window); + XSetWMProtocols(display, window, atoms, 1); + } + } + + @Override + public void close() { + XDestroyWindow(display, window); + } + + @Override + public Event nextEvent(boolean blocking) { + + try ( Frame frame = Frame.frame()) { + XEvent event = XEvent.create(frame); + + while (true) { + if (!blocking && XPending(display) == 0) + return null; + // err this just dies on error + //XWindowEvent(display, window, ~0, event); + int res = XNextEvent(display, event); + + //System.out.printf("next event: %d type %d\n", res, event.getType()); + switch (event.getType()) { + case KeyPress: + return Event.key(event.getXkey().getKeycode()); + case Expose: { + XExposeEvent x = event.getXexpose(); + return Event.expose(x.getX(), x.getY(), x.getWidth(), x.getHeight()); + } + case ConfigureNotify: { + XConfigureEvent x = event.getXconfigure(); + return Event.resize(x.getX(), x.getY(), x.getWidth(), x.getHeight()); + } + case ClientMessage: { + XClientMessageEvent x = event.getXclient(); + + if (x.getMessageType() == wm_protocols + && x.getData().getLElement(0) == wm_delete_window) { + return Event.close(); + } else { + System.out.printf("unknown client message\n"); + } + break; + } + } + } + } + } + + @Override + public VkSurfaceKHR createVulkanSurface(VkInstance instance, ResourceScope scope) { + try ( Frame frame = Frame.frame()) { + VkXlibSurfaceCreateInfoKHR surfaceinfo = VkXlibSurfaceCreateInfoKHR.create(frame, + 0, + display, + window); + + return instance.vkCreateXlibSurfaceKHR(surfaceinfo, scope); + } + } + } +} diff --git a/src/notzed.display/classes/module-info.java b/src/notzed.display/classes/module-info.java new file mode 100644 index 0000000..ac0ced3 --- /dev/null +++ b/src/notzed.display/classes/module-info.java @@ -0,0 +1,8 @@ + +module notzed.display { + requires notzed.xlib; + requires notzed.xcb; + requires notzed.vulkan; + + exports au.notzed.display; +} diff --git a/src/notzed.vulkan.test/classes/module-info.java b/src/notzed.vulkan.test/classes/module-info.java index 452fec9..b21b754 100644 --- a/src/notzed.vulkan.test/classes/module-info.java +++ b/src/notzed.vulkan.test/classes/module-info.java @@ -1,7 +1,7 @@ module notzed.vulkan.test { requires notzed.vulkan; - requires notzed.xlib; - + requires notzed.display; + requires java.desktop; } diff --git a/src/notzed.vulkan.test/classes/vulkan/test/TestCube.java b/src/notzed.vulkan.test/classes/vulkan/test/TestCube.java index 60a1274..df5d7e8 100644 --- a/src/notzed.vulkan.test/classes/vulkan/test/TestCube.java +++ b/src/notzed.vulkan.test/classes/vulkan/test/TestCube.java @@ -1,4 +1,4 @@ - /* +/* The MIT License (MIT) Copyright (C) 2017 Eric Arnebäck @@ -24,51 +24,26 @@ THE SOFTWARE. */ -/* + /* * This is a Java conversion of a C conversion of this: * https://github.com/Erkaman/vulkan_minimal_compute * * It's been simplified a bit and converted to the 'zvk' api. */ - package vulkan.test; -import java.io.InputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.Channels; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import java.awt.Graphics; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.image.MemoryImageSource; -import javax.swing.AbstractAction; -import javax.swing.JComponent; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.KeyStroke; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.Collections; - -import java.lang.invoke.*; +import au.notzed.display.Display; import jdk.incubator.foreign.*; -import jdk.incubator.foreign.MemoryLayout.PathElement; import au.notzed.nativez.*; import vulkan.*; -import static vulkan.VkConstants.*; +import static vulkan.Vulkan.*; -import xlib.*; -import static xlib.XLib.*; +import au.notzed.display.*; import static vulkan.test.GLMaths.*; public class TestCube { + static final boolean debug = true; final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT; @@ -81,7 +56,7 @@ public class TestCube { float projection[] = new float[16]; float view[] = new float[16]; float model[] = new float[16]; - float clip[] = new float[] { + float clip[] = new float[]{ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, @@ -122,7 +97,6 @@ public class TestCube { VkDescriptorPool desc_pool; HandleArray desc_set; - VkRenderPass render_pass; HandleArray framebuffers; @@ -140,7 +114,8 @@ public class TestCube { VkSemaphore chainSemaphore; VkFence drawFence; - record BufferMemory (VkBuffer buffer, VkDeviceMemory memory, long size) { + record BufferMemory(VkBuffer buffer, VkDeviceMemory memory, long size) { + public void free(VkDevice device) { device.vkFreeMemory(memory); device.vkDestroyBuffer(buffer); @@ -152,11 +127,11 @@ public class TestCube { void init_debug() throws Exception { if (!debug) return; - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> { - System.out.printf("Debug: %d: %s\n", severity, data.getMessage()); - return 0; - }, scope); + System.out.printf("Debug: %d: %s\n", severity, data.getMessage()); + return 0; + }, scope); VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame, 0, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT @@ -170,70 +145,35 @@ public class TestCube { } //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *); - } void init_instance() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame, 0, - VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_MAKE_API_VERSION(0, 1, 0, 0)), - new String[] { "VK_LAYER_KHRONOS_validation" }, - new String[] { "VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils" } - ); + VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_API_VERSION_1_0), + new String[]{"VK_LAYER_KHRONOS_validation"}, + new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"} + ); instance = VkInstance.vkCreateInstance(info, scope); System.out.printf("instance = %s\n", instance); } } - XDisplay display; - long window; - long wm_delete_window; + Display display; + Window window; VkSurfaceKHR surface; void init_surface() throws Exception { - try (Frame frame = Frame.frame()) { - XInitThreads(); - display = XOpenDisplay(null); - long visualMask = VisualScreenMask; - IntArray numberOfVisuals = IntArray.createArray(1, frame); - XVisualInfo vInfoTemplate = XVisualInfo.create(frame); - - vInfoTemplate.setScreen(DefaultScreen(display)); - - XVisualInfo visualInfo = XGetVisualInfo(display, visualMask, vInfoTemplate, numberOfVisuals); - long colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.getScreen()), visualInfo.getVisual(), AllocNone); - - XSetWindowAttributes windowAttributes = XSetWindowAttributes.create(frame); - - windowAttributes.setColormap(colormap); - windowAttributes.setBackgroundPixel(0xffffffff); - windowAttributes.setBorderPixel(0); - windowAttributes.setEventMask(KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask); - - window = XCreateWindow(display, RootWindow(display, vInfoTemplate.getScreen()), - 0, 0, width, height, - 0, visualInfo.getDepth(), InputOutput, visualInfo.getVisual(), - CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, windowAttributes); - - XSelectInput(display, window, ExposureMask | KeyPressMask); - XMapWindow(display, window); - XFlush(display); - wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0); - - VkXlibSurfaceCreateInfoKHR surfaceinfo = VkXlibSurfaceCreateInfoKHR.create(frame, - 0, - display, - window); - - surface = instance.vkCreateXlibSurfaceKHR(surfaceinfo, scope); - System.out.printf("surface: %s\n", surface); - } + display = Display.createX11Display(); + window = display.createWindow(width, height); + surface = window.createVulkanSurface(instance, scope); + System.out.printf("surface: %s\n", surface); } void init_device() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { IntArray count$h = IntArray.create(frame, 1); IntArray present$h = IntArray.create(frame, 1); HandleArray devs; @@ -293,7 +233,7 @@ public class TestCube { 0, graphics_queue, qpri); - String [] extensions = { + String[] extensions = { "VK_KHR_swapchain" }; VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame); @@ -344,8 +284,7 @@ public class TestCube { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - }; + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,}; for (int flag: compositeAlphaFlags) { if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) { compositeAlpha = flag; @@ -416,7 +355,7 @@ public class TestCube { } void init_command() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame, 0, graphics_queue_index); @@ -434,7 +373,7 @@ public class TestCube { // parameterise as init_image? void init_depth() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { int format = VK_FORMAT_D16_UNORM; VkMemoryRequirements req = VkMemoryRequirements.create(frame); VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0, @@ -489,7 +428,7 @@ public class TestCube { } void init_descriptor() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { HandleArray layout_table = VkDescriptorSetLayout.createArray(1, frame); VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame, 0, @@ -548,7 +487,7 @@ public class TestCube { } void init_render() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame); attachments.setFormat(chainImageFormat); @@ -601,7 +540,7 @@ public class TestCube { } void init_framebuffer() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { HandleArray attachments = VkImageView.createArray(2, frame); attachments.setAtIndex(1, depthView); @@ -626,7 +565,7 @@ public class TestCube { } void init_vertexbuffer() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { vertex = init_buffer(Cube.data.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(Cube.data)); vertexBuffer.setAtIndex(0, vertex.buffer); @@ -649,7 +588,7 @@ public class TestCube { void init_pipeline() throws Exception { int res; - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { IntArray dynamicStateEnables = IntArray.create(frame, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR); @@ -739,7 +678,7 @@ public class TestCube { null, 0, //.alphaToCoverageEnable = VK_FALSE, 0 //.alphaToOneEnable = VK_FALSE, - ); + ); VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame, 0, @@ -756,12 +695,10 @@ public class TestCube { VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope); // FIXME: createArray should initialise this - shaderStages.setSType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO); shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT); shaderStages.setName("main", (SegmentAllocator)scope); shaderStages.setModule(shader.get(0)); - shaderStages.setSTypeAtIndex(1, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO); shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope); shaderStages.setModuleAtIndex(1, shader.get(1)); @@ -795,10 +732,9 @@ public class TestCube { } } - void execute_begin_command_buffer() throws Exception { /* DEPENDS on init_command() */ - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame, 0, null); @@ -817,9 +753,8 @@ public class TestCube { int res; /* Queue the command buffer for execution */ - /* FIXME: frame shoudl provide or take explicit scope */ - try (ResourceScope scope = ResourceScope.newConfinedScope(); - Frame frame = Frame.frame()) { + /* FIXME: frame shoudl provide or take explicit scope */ + try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) { IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0); HandleArray fences = VkFence.createArray(1, frame); @@ -842,7 +777,7 @@ public class TestCube { } void cmd_viewport() { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkCommandBuffer cmd = this.cmd.getAtIndex(0); VkViewport viewport = VkViewport.create(frame, 0, 0, width, height, 0.0f, 1.0f); @@ -851,7 +786,7 @@ public class TestCube { } void cmd_scissors() { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkCommandBuffer cmd = this.cmd.getAtIndex(0); VkRect2D scissor = VkRect2D.create(frame); VkExtent2D extent = scissor.getExtent(); @@ -865,7 +800,7 @@ public class TestCube { void cmd_paint() throws Exception { int res; - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { int chainIndex; IntArray chainIndices = IntArray.createArray(1, frame); VkCommandBuffer cmd = this.cmd.getAtIndex(0); @@ -951,10 +886,10 @@ public class TestCube { * 1) create buffer, specifying usage and size * 2) allocate memory based on memory requirements * 3) bind memory - * + *

*/ BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkMemoryRequirements req = VkMemoryRequirements.create(frame); VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame, 0, @@ -991,13 +926,13 @@ public class TestCube { device.vkDestroySemaphore(chainSemaphore); device.vkDestroyPipeline(pipeline.getAtIndex(0)); - for (int i=0;i commandBuffers; - record BufferMemory ( VkBuffer buffer, VkDeviceMemory memory ) {}; + record BufferMemory(VkBuffer buffer, VkDeviceMemory memory) { + + } VkDebugUtilsMessengerEXT logger; void init_debug() throws Exception { if (!debug) return; - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> { - System.out.printf("Debug: %d: %s\n", severity, data.getMessage()); - return 0; - }, scope); + System.out.printf("Debug: %d: %s\n", severity, data.getMessage()); + return 0; + }, scope); VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame, 0, //VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | @@ -127,20 +120,20 @@ public class TestMandelbrot { } void init_instance() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame, 0, - VkApplicationInfo.create(frame, "test", 1, "test-engine", 2, VK_MAKE_API_VERSION(0, 1, 0, 0)), - new String[] { "VK_LAYER_KHRONOS_validation" }, - debug ? new String[] { "VK_EXT_debug_utils" } : null - ); + VkApplicationInfo.create(frame, "test", 1, "test-engine", 2, VK_API_VERSION_1_0), + new String[]{"VK_LAYER_KHRONOS_validation"}, + debug ? new String[]{"VK_EXT_debug_utils"} : null + ); instance = VkInstance.vkCreateInstance(info, scope); } } void init_device() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { HandleArray devs; int count; int res; @@ -151,12 +144,12 @@ public class TestMandelbrot { int devid = -1; int queueid = -1; - for (int i=0;i */ BufferMemory init_buffer(long dataSize, int usage, int properties) throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkMemoryRequirements req = VkMemoryRequirements.create(frame); VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame, 0, @@ -241,13 +234,13 @@ public class TestMandelbrot { /** * Descriptors are used to bind and describe memory blocks * to shaders. - * + *

* *Pool is used to allocate descriptors, it is per-device. * *Layout is used to group descriptors for a given pipeline, * The descriptors describe individually-addressable blocks. */ void init_descriptor() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { /* Create descriptorset layout */ VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame, 0, @@ -308,10 +301,10 @@ public class TestMandelbrot { } /** - * Create the compute pipeline. This is the shader and data layouts for it. + * Create the compute pipeline. This is the shader and data layouts for it. */ void init_pipeline() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { /* Set shader code */ VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame, 0, @@ -353,7 +346,7 @@ public class TestMandelbrot { * Create a command buffer, this is somewhat like a display list. */ void init_command_buffer() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame, 0, computeQueueIndex); @@ -388,11 +381,11 @@ public class TestMandelbrot { /** * Execute the pre-created command buffer. - * + *

* A fence is used to wait for completion. */ void execute() throws Exception { - try (Frame frame = Frame.frame()) { + try ( Frame frame = Frame.frame()) { VkSubmitInfo submitInfo = VkSubmitInfo.create(frame); submitInfo.setCommandBufferCount(1); @@ -443,7 +436,7 @@ public class TestMandelbrot { * Accesses the gpu buffer, converts it to RGB byte, and saves it as a pam file. */ void save_result() throws Exception { - try (ResourceScope scope = ResourceScope.newConfinedScope()) { + try ( ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment mem = device.vkMapMemory(dst.memory(), 0, dstBufferSize, 0, scope); byte[] pixels = new byte[WIDTH * HEIGHT * 3]; @@ -462,7 +455,7 @@ public class TestMandelbrot { } void show_result() throws Exception { - try (ResourceScope scope = ResourceScope.newConfinedScope()) { + try ( ResourceScope scope = ResourceScope.newConfinedScope()) { MemorySegment mem = device.vkMapMemory(dst.memory(), 0, dstBufferSize, 0, scope); int[] pixels = new int[WIDTH * HEIGHT]; @@ -480,7 +473,7 @@ public class TestMandelbrot { * Trivial pnm format image output. */ void pam_save(String name, int width, int height, int depth, byte[] pixels) throws IOException { - try (FileOutputStream fos = new FileOutputStream(name)) { + try ( FileOutputStream fos = new FileOutputStream(name)) { fos.write(String.format("P6\n%d\n%d\n255\n", width, height).getBytes()); fos.write(pixels); System.out.printf("wrote: %s\n", name); @@ -523,28 +516,6 @@ public class TestMandelbrot { window.setVisible(true); } - IntArray loadSPIRV0(String name) throws IOException { - // hmm any way to just load this directly? - try (InputStream is = TestMandelbrot.class.getResourceAsStream(name)) { - ByteBuffer bb = ByteBuffer.allocateDirect(8192).order(ByteOrder.nativeOrder()); - int length = Channels.newChannel(is).read(bb); - - bb.position(0); - bb.limit(length); - - return IntArray.create(MemorySegment.ofByteBuffer(bb)); - } - } - - IntArray loadSPIRV(String name) throws IOException { - try (InputStream is = TestMandelbrot.class.getResourceAsStream(name)) { - MemorySegment seg = ((SegmentAllocator)scope).allocateArray(Memory.INT, 2048); - int length = Channels.newChannel(is).read(seg.asByteBuffer()); - - return IntArray.create(seg.asSlice(0, length)); - } - } - /** * This finds the memory type index for the memory on a specific device. */ @@ -558,12 +529,8 @@ public class TestMandelbrot { return -1; } - public static int VK_MAKE_API_VERSION(int variant, int major, int minor, int patch) { - return (variant << 29) | (major << 22) | (minor << 12) | patch; - } - void demo() throws Exception { - mandelbrot_cs = loadSPIRV("mandelbrot.bin"); + mandelbrot_cs = ShaderIO.loadMandelbrot((SegmentAllocator)scope); init_instance(); init_debug(); @@ -590,7 +557,6 @@ public class TestMandelbrot { shutdown(); } - public static void main(String[] args) throws Throwable { System.loadLibrary("vulkan"); diff --git a/src/notzed.vulkan.test/classes/vulkan/test/TestSDF.java b/src/notzed.vulkan.test/classes/vulkan/test/TestSDF.java new file mode 100644 index 0000000..a947ff7 --- /dev/null +++ b/src/notzed.vulkan.test/classes/vulkan/test/TestSDF.java @@ -0,0 +1,1056 @@ +/* +The MIT License (MIT) + +Copyright (C) 2017 Eric Arnebäck +Copyright (C) 2019 Michael Zucchi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + */ + + /* + * This is a Java conversion of a C conversion of this: + * https://github.com/Erkaman/vulkan_minimal_compute + * + * It's been simplified a bit and converted to the 'zvk' api. + */ +package vulkan.test; + +import au.notzed.display.Display; +import au.notzed.display.Event; +import au.notzed.display.Window; +import jdk.incubator.foreign.*; +import au.notzed.nativez.*; + +import vulkan.*; +import static vulkan.Vulkan.*; + +import static vulkan.test.GLMaths.*; + +public class TestSDF { + + static final boolean debug = true; + + final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT; + final static int NUM_DESCRIPTOR_SETS = 1; + + ResourceScope scope = ResourceScope.newSharedScope(); + + int width = 800; + int height = 800; + float projection[] = new float[16]; + float view[] = new float[16]; + float model[] = new float[16]; + float clip[] = new float[]{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f, + 0.0f, 0.0f, 0.5f, 1.0f + }; + float mvp[] = new float[16]; + + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkPhysicalDeviceMemoryProperties memory_properties; + VkPhysicalDeviceFeatures device_features; + + int present_queue_index; + int graphics_queue_index; + + VkDevice device; + VkSwapchainKHR chain; + + VkQueue graphics_queue; + VkQueue present_queue; + + int chainImageFormat; + HandleArray chainImage; + HandleArray chainImageView; + + int depthFormat; + VkImage depthImage; + VkImageView depthView; + VkDeviceMemory depthMemory; + + VkCommandPool cmd_pool; + HandleArray cmd; + + BufferMemory uniform; + VkPipelineLayout pipeline_layout; + + VkDescriptorSetLayout desc_layout; + VkDescriptorPool desc_pool; + HandleArray desc_set; + + VkRenderPass render_pass; + HandleArray framebuffers; + + BufferMemory vertex; + HandleArray vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope); + VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope); + VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(1, (SegmentAllocator)scope); + + IntArray sdf_vs; + IntArray sdf_fs; + HandleArray shader = VkShaderModule.createArray(2, (SegmentAllocator)scope); + + HandleArray pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope); + + VkSemaphore chainSemaphore; + VkFence drawFence; + + record BufferMemory(VkBuffer buffer, VkDeviceMemory memory, long size) { + + public void free(VkDevice device) { + device.vkFreeMemory(memory); + device.vkDestroyBuffer(buffer); + } + } + + VkDebugUtilsMessengerEXT logger; + + void init_debug() throws Exception { + if (!debug) + return; + try ( Frame frame = Frame.frame()) { + var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> { + System.out.printf("Debug: %d: %s\n", severity, data.getMessage()); + return 0; + }, scope); + VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame, + 0, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + cb, + null); + + logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope); + } + + //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *); + } + + void init_instance() throws Exception { + try ( Frame frame = Frame.frame()) { + VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame, + 0, + VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_API_VERSION_1_0), + new String[]{"VK_LAYER_KHRONOS_validation"}, + new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"} + ); + + instance = VkInstance.vkCreateInstance(info, scope); + System.out.printf("instance = %s\n", instance); + } + } + + Display display; + Window window; + VkSurfaceKHR surface; + + void init_surface() throws Exception { + display = Display.createX11Display(); + window = display.createWindow(width, height); + surface = window.createVulkanSurface(instance, scope); + System.out.printf("surface: %s\n", surface); + } + + void init_device() throws Exception { + try ( Frame frame = Frame.frame()) { + IntArray count$h = IntArray.create(frame, 1); + IntArray present$h = IntArray.create(frame, 1); + HandleArray devs; + int count; + int res; + + devs = instance.vkEnumeratePhysicalDevices(frame, scope); + + // Search for device and queue indices + int devid = -1; + int present_queue = -1; + int graphics_queue = -1; + for (int i = 0; i < devs.length(); i++) { + VkPhysicalDevice dev = devs.getAtIndex(i); + VkQueueFamilyProperties famprops; + + famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame); + + for (int j = 0; j < famprops.length(); j++) { + boolean present; + + dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h); + present = present$h.get(0) != 0; + + if (present && present_queue == -1) + present_queue = j; + if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) { + graphics_queue = j; + if (present) { + present_queue = j; + break; + } + } + } + if (present_queue != -1 && graphics_queue != -1) { + devid = i; + break; + } + } + + if (devid == -1) + throw new Exception("Cannot find a suitable device"); + + physicalDevice = devs.getAtIndex(devid); + present_queue_index = present_queue; + graphics_queue_index = graphics_queue; + + // NOTE: app scope + memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope); + physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties); + device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope); + physicalDevice.vkGetPhysicalDeviceFeatures(device_features); + + FloatArray qpri = FloatArray.create(frame, 0.0f); + VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create( + frame, + 0, + graphics_queue, + qpri); + String[] extensions = { + "VK_KHR_swapchain" + }; + VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame); + features.setDepthClamp(1); + VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create( + frame, + 0, + qinfo, + null, + extensions, + features); + + device = physicalDevice.vkCreateDevice(devinfo, scope); + + System.out.printf("device = %s\n", device); + + /* ************************************************************** */ + int format; + VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame); + // If the format list includes just one entry of VK_FORMAT_UNDEFINED, + // the surface has no preferred format. Otherwise, at least one + // supported format will be returned. + if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) { + format = VK_FORMAT_B8G8R8A8_UNORM; + } else { + format = surfFormats.getFormatAtIndex(0); + } + + VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame); + + physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities); + IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame); + + VkExtent2D swapchainExtent; + // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. + if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) { + // If the surface size is undefined, the size is set to + // the size of the images requested. + swapchainExtent = VkExtent2D.create(frame, + clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()), + clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight())); + } else { + // If the surface size is defined, the swap chain size must match + swapchainExtent = surfCapabilities.getCurrentExtent(); + } + int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + int compositeAlphaFlags[] = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,}; + for (int flag: compositeAlphaFlags) { + if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) { + compositeAlpha = flag; + break; + } + } + + VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(frame, + 0, + surface, + surfCapabilities.getMinImageCount(), + format, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + 1, //.imageArrayLayers = 1, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_SHARING_MODE_EXCLUSIVE, + // assumes queues are same. + null, + (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0 + ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(), + compositeAlpha, + VK_PRESENT_MODE_FIFO_KHR, + VK_TRUE, + null); + chaininfo.getImageExtent().setWidth(swapchainExtent.getWidth()); + chaininfo.getImageExtent().setHeight(swapchainExtent.getHeight()); + + chain = device.vkCreateSwapchainKHR(chaininfo, scope); + + int chainImageCount; + + chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope); + chainImageCount = (int)chainImage.length(); + chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope); + + VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, + 0, + null, + VK_IMAGE_VIEW_TYPE_2D, + format); + VkComponentMapping components = viewinfo.getComponents(); + components.setR(VK_COMPONENT_SWIZZLE_R); + components.setG(VK_COMPONENT_SWIZZLE_G); + components.setB(VK_COMPONENT_SWIZZLE_B); + components.setA(VK_COMPONENT_SWIZZLE_A); + VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange(); + subresourceRange.setAspectMask(VK_IMAGE_ASPECT_COLOR_BIT); + subresourceRange.setLevelCount(1); + subresourceRange.setLayerCount(1); + + for (int i = 0; i < chainImageCount; i++) { + viewinfo.setImage(chainImage.get(i)); + + chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope)); + } + + chainImageFormat = format; + } + } + + void init_device_queue() { + graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope); + if (graphics_queue_index == present_queue_index) { + present_queue = graphics_queue; + } else { + present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope); + } + } + + void init_command() throws Exception { + try ( Frame frame = Frame.frame()) { + VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame, + 0, + graphics_queue_index); + + cmd_pool = device.vkCreateCommandPool(poolinfo, scope); + + VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame, + cmd_pool, + VK_COMMAND_BUFFER_LEVEL_PRIMARY, + 1); + + cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope); + } + } + + // parameterise as init_image? + void init_depth() throws Exception { + try ( Frame frame = Frame.frame()) { + int format = VK_FORMAT_D16_UNORM; + VkMemoryRequirements req = VkMemoryRequirements.create(frame); + VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0, + VK_IMAGE_TYPE_2D, + format, + 1, + 1, + NUM_SAMPLES, + 0, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_SHARING_MODE_EXCLUSIVE, + null, + VK_IMAGE_LAYOUT_UNDEFINED); + imageinfo.getExtent().setWidth(width); + imageinfo.getExtent().setHeight(height); + imageinfo.getExtent().setDepth(1); + + depthImage = device.vkCreateImage(imageinfo, scope); + + device.vkGetImageMemoryRequirements(depthImage, req); + VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame, + req.getSize(), + find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); + + depthMemory = device.vkAllocateMemory(alloc, scope); + + device.vkBindImageMemory(depthImage, depthMemory, 0); + + VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, 0, + depthImage, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_D16_UNORM); + + VkComponentMapping components = viewinfo.getComponents(); + components.setR(VK_COMPONENT_SWIZZLE_R); + components.setG(VK_COMPONENT_SWIZZLE_G); + components.setB(VK_COMPONENT_SWIZZLE_B); + components.setA(VK_COMPONENT_SWIZZLE_A); + VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange(); + subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); + subresourceRange.setLevelCount(1); + subresourceRange.setLayerCount(1); + + depthView = device.vkCreateImageView(viewinfo, scope); + + depthFormat = format; + } + } + + void init_uniform() throws Exception { + uniform = init_buffer(mvp.length * 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(mvp)); + } + + void init_descriptor() throws Exception { + try ( Frame frame = Frame.frame()) { + HandleArray layout_table = VkDescriptorSetLayout.createArray(1, frame); + VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame, + 0, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 1, + VK_SHADER_STAGE_VERTEX_BIT, + null); + VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(frame, + 0, + layout_binding); + + desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope); + layout_table.setAtIndex(0, desc_layout); + + VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame, + 0, + //1, + layout_table, + null); + + pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope); + + VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(frame, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 1); + + VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(frame, + 0, + 1, + type_count); + + desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope); + + VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame, + desc_pool, + //1, + layout_table); + + System.out.println(alloc_info); + + desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope); + + VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(frame, uniform.buffer, 0, uniform.size); + VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(frame, + desc_set.getAtIndex(0), + 0, + 0, + 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + null, + uniformInfo, + null); + + device.vkUpdateDescriptorSets(1, writes, 0, null); + } + } + + void init_render() throws Exception { + try ( Frame frame = Frame.frame()) { + VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame); + + attachments.setFormat(chainImageFormat); + attachments.setSamples(NUM_SAMPLES); + attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR); + attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE); + attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE); + attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE); + attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED); + attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + attachments.setFlags(0); + + attachments.setFormatAtIndex(1, depthFormat); + attachments.setSamplesAtIndex(1, NUM_SAMPLES); + attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR); + attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE); + attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); + attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE); + attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED); + attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + attachments.setFlagsAtIndex(1, 0); + + VkAttachmentReference color_reference = VkAttachmentReference.create(frame, + 0, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + VkAttachmentReference depth_reference = VkAttachmentReference.create(frame, + 1, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + VkSubpassDescription subpass = VkSubpassDescription.create(frame, + 0, + VK_PIPELINE_BIND_POINT_GRAPHICS, + null, + 1, + color_reference, + null, + depth_reference, + null); + + VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(frame, + 0, + //(int)attachments.length(), + attachments, + subpass, + null); + + render_pass = device.vkCreateRenderPass(rp_info, scope); + } + } + + void init_framebuffer() throws Exception { + try ( Frame frame = Frame.frame()) { + HandleArray attachments = VkImageView.createArray(2, frame); + + attachments.setAtIndex(1, depthView); + + // FIXME: I don't think i want lenghts implied for types tbh + VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(frame, + 0, + render_pass, + //2, + attachments, + width, + height, + 1); + + framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope); + for (int i = 0; i < chainImage.size(); i++) { + attachments.setAtIndex(0, chainImageView.get(i)); + framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope)); + System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i)); + } + } + } + + void init_vertexbuffer() throws Exception { + try ( Frame frame = Frame.frame()) { + float[] image = { + -1, -1, 0, 1, + 1, -1, 0, 1, + -1, 1, 0, 1, + -1, 1, 0, 1, + 1, -1, 0, 1, + 1, 1, 0, 1 + // 1, -1, 0, 1, + // -1, 1, 0, 1, + // 1, 1, 0, 1 + }; + vertex = init_buffer(image.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(image)); + + vertexBuffer.setAtIndex(0, vertex.buffer); + + /* ***************************************** */ + vi_binding.setBinding(0); + vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX); + vi_binding.setStride(4 * 4); + + vi_attribs.setBinding(0); + vi_attribs.setLocation(0); + vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT); + vi_attribs.setOffset(0); + //vi_attribs.setBindingAtIndex(1, 0); + //vi_attribs.setLocationAtIndex(1, 1); + //vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT); + //vi_attribs.setOffsetAtIndex(1, 16); + } + } + + void init_pipeline() throws Exception { + int res; + try ( Frame frame = Frame.frame()) { + IntArray dynamicStateEnables = IntArray.create(frame, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR); + + VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(frame, + 0, dynamicStateEnables); + + VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(frame, + 0, + vi_binding, + vi_attribs); + + VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(frame, + 0, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + 0); + + VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(frame, + 0, + VK_TRUE, + VK_FALSE, + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_BACK_BIT, + VK_FRONT_FACE_CLOCKWISE, + VK_FALSE, + 0.0f, + 0.0f, + 0.0f, + 1.0f); + + VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(frame, + VK_FALSE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + 0xf); + + VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(frame, + 0, + VK_FALSE, + VK_LOGIC_OP_NO_OP, + att_state, + 1.0f, 1.0f, 1.0f, 1.0f); + + VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame, + 0, + 1, null, + 1, null); + + VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(frame, + 0, + VK_TRUE, + VK_TRUE, + VK_COMPARE_OP_LESS_OR_EQUAL, + VK_FALSE, + VK_FALSE, + 0.0f, + 0.0f); + VkStencilOpState back = ds.getBack(); + + back.setFailOp(VK_STENCIL_OP_KEEP); + back.setPassOp(VK_STENCIL_OP_KEEP); + back.setCompareOp(VK_COMPARE_OP_ALWAYS); + back.setCompareMask(0); + back.setReference(0); + back.setDepthFailOp(VK_STENCIL_OP_KEEP); + back.setWriteMask(0); + + VkStencilOpState front = ds.getFront(); + + front.setFailOp(VK_STENCIL_OP_KEEP); + front.setPassOp(VK_STENCIL_OP_KEEP); + front.setCompareOp(VK_COMPARE_OP_ALWAYS); + front.setCompareMask(0); + front.setReference(0); + front.setDepthFailOp(VK_STENCIL_OP_KEEP); + front.setWriteMask(0); + + VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(frame, + 0, + NUM_SAMPLES, + 0, //.sampleShadingEnable = VK_FALSE, + 0.0f, + null, + 0, //.alphaToCoverageEnable = VK_FALSE, + 0 //.alphaToOneEnable = VK_FALSE, + ); + + VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame, + 0, + sdf_vs.length() * 4, + sdf_vs); + VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(frame, + 0, + sdf_fs.length() * 4, + sdf_fs); + + shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope)); + shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope)); + + VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope); + + // FIXME: createArray should initialise this + shaderStages.setSType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO); + shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT); + shaderStages.setName("main", (SegmentAllocator)scope); + shaderStages.setModule(shader.get(0)); + + shaderStages.setSTypeAtIndex(1, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO); + shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT); + shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope); + shaderStages.setModuleAtIndex(1, shader.get(1)); + + VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(frame, + 0, + //2, shaderStages, + shaderStages, + vi, + ia, + null, + vp, + rs, + ms, + ds, + cb, + dynamicState, + pipeline_layout, + render_pass, + 0, + null, + 0); + + res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline); + + VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0); + chainSemaphore = device.vkCreateSemaphore(seminfo, scope); + + VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0); + drawFence = device.vkCreateFence(fenceInfo, scope); + } + } + + void execute_begin_command_buffer() throws Exception { + /* DEPENDS on init_command() */ + try ( Frame frame = Frame.frame()) { + VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame, + 0, + null); + + cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info); + } + } + + void execute_end_command_buffer() throws Exception { + cmd.getAtIndex(0).vkEndCommandBuffer(); + } + + final static long FENCE_TIMEOUT = 100000000; + + void execute_queue_command_buffer() throws Exception { + int res; + + /* Queue the command buffer for execution */ + /* FIXME: frame shoudl provide or take explicit scope */ + try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) { + IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0); + HandleArray fences = VkFence.createArray(1, frame); + + fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope)); + + VkSubmitInfo submit_info = VkSubmitInfo.create(frame, + 1, null, pipe_stage_flags, + cmd, + null); + + graphics_queue.vkQueueSubmit(1, submit_info, drawFence); + + do { + res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT); + } while (res == VK_TIMEOUT); + + device.vkDestroyFence(fences.getAtIndex(0)); + } + } + + void cmd_viewport() { + try ( Frame frame = Frame.frame()) { + VkCommandBuffer cmd = this.cmd.getAtIndex(0); + VkViewport viewport = VkViewport.create(frame, + 0, 0, width, height, 0.0f, 1.0f); + cmd.vkCmdSetViewport(0, 1, viewport); + } + } + + void cmd_scissors() { + try ( Frame frame = Frame.frame()) { + VkCommandBuffer cmd = this.cmd.getAtIndex(0); + VkRect2D scissor = VkRect2D.create(frame); + VkExtent2D extent = scissor.getExtent(); + + extent.setWidth(width); + extent.setHeight(height); + + cmd.vkCmdSetScissor(0, 1, scissor); + } + } + + void cmd_paint() throws Exception { + int res; + try ( Frame frame = Frame.frame()) { + int chainIndex; + IntArray chainIndices = IntArray.createArray(1, frame); + VkCommandBuffer cmd = this.cmd.getAtIndex(0); + + device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices); + chainIndex = chainIndices.getAtIndex(0); + LongArray offsets = LongArray.createArray(1, frame); + + VkClearValue clear_values = VkClearValue.createArray(2, frame); + FloatArray col = clear_values.getColor().getFloat32(); + col.setAtIndex(0, 0.2f); + col.setAtIndex(1, 0.2f); + col.setAtIndex(2, 0.2f); + col.setAtIndex(3, 0.2f); + VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil(); + depthStencil.setDepth(1.0f); + depthStencil.setStencil(0); + + System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex)); + + VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(frame, + render_pass, + framebuffers.getAtIndex(chainIndex), + clear_values); + VkExtent2D extent = rp_begin.getRenderArea().getExtent(); + extent.setWidth(width); + extent.setHeight(height); + + cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE); + + cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0)); + cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null); + cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets); + + cmd_viewport(); + cmd_scissors(); + + cmd.vkCmdDraw(12 * 3, 1, 0, 0); + cmd.vkCmdEndRenderPass(); + + cmd.vkEndCommandBuffer(); + + IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + HandleArray semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope); + + semaphores.setAtIndex(0, chainSemaphore); + + VkSubmitInfo submit_info = VkSubmitInfo.create(frame, + 1, semaphores, pipe_stage_flags, + this.cmd, + null); + + HandleArray fences = VkFence.createArray(1, frame); + + fences.setAtIndex(0, drawFence); + + // Queue the command buffer for execution + device.vkResetFences(1, fences); + + graphics_queue.vkQueueSubmit(1, submit_info, drawFence); + + // Make sure command buffer is finished before presenting + do { + res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT); + } while (res == VK_TIMEOUT); + + // Now present the image in the window + HandleArray chains = VkSwapchainKHR.createArray(1, frame); + chains.setAtIndex(0, chain); + VkPresentInfoKHR present = VkPresentInfoKHR.create(frame, + null, + 1, + chains, + chainIndices, + null); + + present_queue.vkQueuePresentKHR(present); + } + } + + /** + * Buffers are created in three steps: + * 1) create buffer, specifying usage and size + * 2) allocate memory based on memory requirements + * 3) bind memory + *

+ */ + BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception { + try ( Frame frame = Frame.frame()) { + VkMemoryRequirements req = VkMemoryRequirements.create(frame); + VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame, + 0, + dataSize, + usage, + VK_SHARING_MODE_EXCLUSIVE, + //0, + null); + + VkBuffer buffer = device.vkCreateBuffer(buf_info, scope); + + device.vkGetBufferMemoryRequirements(buffer, req); + + VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame, + req.getSize(), + find_memory_type(memory_properties, req.getMemoryTypeBits(), properties)); + + VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope); + + if (init != null) { + MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope); + mem.copyFrom(init); + device.vkUnmapMemory(memory); + } + + device.vkBindBufferMemory(buffer, memory, 0); + + return new BufferMemory(buffer, memory, dataSize); + } + } + + void shutdown() { + device.vkDestroyFence(drawFence); + device.vkDestroySemaphore(chainSemaphore); + + device.vkDestroyPipeline(pipeline.getAtIndex(0)); + for (int i = 0; i < shader.size(); i++) + device.vkDestroyShaderModule(shader.getAtIndex(i)); + + vertex.free(device); + uniform.free(device); + + for (int i = 0; i < framebuffers.size(); i++) + device.vkDestroyFramebuffer(framebuffers.getAtIndex(i)); + + device.vkDestroyRenderPass(render_pass); + + device.vkDestroyDescriptorPool(desc_pool); + device.vkDestroyPipelineLayout(pipeline_layout); + device.vkDestroyDescriptorSetLayout(desc_layout); + + device.vkDestroyImageView(depthView); + device.vkFreeMemory(depthMemory); + device.vkDestroyImage(depthImage); + + for (int i = 0; i < chainImageView.size(); i++) + device.vkDestroyImageView(chainImageView.getAtIndex(i)); + + device.vkDestroySwapchainKHR(chain); + + device.vkDestroyCommandPool(cmd_pool); + device.vkDestroyDevice(); + + instance.vkDestroySurfaceKHR(surface); + window.close(); + display.close(); + + if (logger != null) + instance.vkDestroyDebugUtilsMessengerEXT(logger); + instance.vkDestroyInstance(); + } + + /** + * This finds the memory type index for the memory on a specific device. + */ + static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) { + VkMemoryType mtypes = memory.getMemoryTypes(); + + for (int i = 0; i < memory.getMemoryTypeCount(); i++) { + if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query)) + return i; + } + return -1; + } + + static int clampi(int v, int min, int max) { + return v < min ? min : v < max ? v : max; + } + + void init_matrices() { + //float eye[] = new float[] {-5, 3, -10}; + float eye[] = new float[]{0, 0, -10}; + float centre[] = new float[]{0, 0, 0}; + float up[] = new float[]{0, -1, 0}; + float t0[] = new float[16], t1[] = new float[16]; + + perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f); + lookAt(view, eye, centre, up); + identity4f(model); + mult4x4f(t0, clip, projection); + mult4x4f(t1, t0, view); + mult4x4f(mvp, t1, model); + } + + void demo() throws Exception { + sdf_vs = ShaderIO.loadSdf_vs((SegmentAllocator)scope); + sdf_fs = ShaderIO.loadSdf_fs((SegmentAllocator)scope); + + init_matrices(); + + init_instance(); + init_debug(); + + init_surface(); + init_device(); + init_device_queue(); + init_command(); + init_depth(); + init_uniform(); + + init_descriptor(); + init_render(); + init_framebuffer(); + init_vertexbuffer(); + init_pipeline(); + + execute_begin_command_buffer(); + + cmd_paint(); + + System.out.println("Any key to quit"); + Event e; +outer: while ((e = window.nextEvent(true)) != null) { + switch (e.type) { + case Event.KEY: + case Event.CLOSE: + break outer; + } + } + + shutdown(); + } + + public static void main(String[] args) throws Throwable { + System.loadLibrary("vulkan"); + System.loadLibrary("X11"); + + new TestSDF().demo(); + } +} diff --git a/src/notzed.vulkan.test/gen/gen.make b/src/notzed.vulkan.test/gen/gen.make index 1abdde1..e5c948f 100644 --- a/src/notzed.vulkan.test/gen/gen.make +++ b/src/notzed.vulkan.test/gen/gen.make @@ -15,3 +15,28 @@ bin/modules/notzed.vulkan.test/vulkan/test/cube_vs.bin: src/notzed.vulkan.test/g bin/modules/notzed.vulkan.test/vulkan/test/cube_fs.bin: src/notzed.vulkan.test/gen/cube.frag mkdir -p $(@D) glslangValidator --target-env vulkan1.0 -V -o $@ $< + +bin/modules/notzed.vulkan.test/vulkan/test/sdf_vs.bin: src/notzed.vulkan.test/gen/sdf.vert + mkdir -p $(@D) + glslangValidator --target-env vulkan1.0 -V -o $@ $< + +bin/modules/notzed.vulkan.test/vulkan/test/sdf_fs.bin: src/notzed.vulkan.test/gen/sdf.frag + mkdir -p $(@D) + glslangValidator --target-env vulkan1.0 -V -o $@ $< + +bin/status/notzed.vulkan.test.classes: \ + bin/gen/notzed.vulkan.test/classes/vulkan/test/ShaderIO.java + +# Note: different to above, in classes dir for netbeans to find +notzed.vulkan.test_SHADERS = \ + bin/gen/notzed.vulkan.test/classes/vulkan/test/mandelbrot.bin \ + bin/gen/notzed.vulkan.test/classes/vulkan/test/cube_vs.bin \ + bin/gen/notzed.vulkan.test/classes/vulkan/test/cube_fs.bin \ + bin/gen/notzed.vulkan.test/classes/vulkan/test/sdf_vs.bin \ + bin/gen/notzed.vulkan.test/classes/vulkan/test/sdf_fs.bin + +bin/gen/notzed.vulkan.test/classes/vulkan/test/ShaderIO.java: $(notzed.vulkan.test_SHADERS) src/notzed.vulkan.test/gen/generate-shaderio + src/notzed.vulkan.test/gen/generate-shaderio $@ $(notzed.vulkan.test_SHADERS) + +bin/gen/notzed.vulkan.test/classes/vulkan/test/%: bin/modules/notzed.vulkan.test/vulkan/test/% + install -D $< $@ diff --git a/src/notzed.vulkan.test/gen/generate-shaderio b/src/notzed.vulkan.test/gen/generate-shaderio new file mode 100755 index 0000000..0da17b3 --- /dev/null +++ b/src/notzed.vulkan.test/gen/generate-shaderio @@ -0,0 +1,46 @@ +#!/usr/bin/perl + +# probably should take scope + +use strict; + +use File::Path qw(make_path); +use File::Basename; + +my $path = shift; + +open my $f, ">", $path || die; + +print $f <= 0) { + my $file = shift; + my $func = ucfirst(basename($file, '.bin')); + my $name = basename($file); + my $size = (stat($file))[7]; + + print $f "\tstatic IntArray load$func(SegmentAllocator alloc) throws IOException { return loadSPIRV(\"$name\", $size, alloc); }\n"; +} + +print $f "}\n"; + +close $f; diff --git a/src/notzed.vulkan.test/gen/sdf.frag b/src/notzed.vulkan.test/gen/sdf.frag new file mode 100644 index 0000000..b453bd2 --- /dev/null +++ b/src/notzed.vulkan.test/gen/sdf.frag @@ -0,0 +1,21 @@ +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +layout (location = 0) out vec4 outColor; + +void main() { + vec2 res = vec2(800, 800); + vec2 uv = (gl_FragCoord.xy - 0.5 * res) * (1.0 / 400.0); + + float d = max(-(length(uv) - 0.5), length(uv + vec2(0.1, 0.1)) - 0.6); + + if (d < 0) { + outColor = vec4(0, 0, 1, 1); + } else { + outColor = vec4(1, 0, 0, 1); + } + + + //outColor = vec4(1, 0, 1, 1); + //outColor = vec4(gl_FragCoord.xy * 1.0 / 500.0, 0, 1); +} diff --git a/src/notzed.vulkan.test/gen/sdf.vert b/src/notzed.vulkan.test/gen/sdf.vert new file mode 100644 index 0000000..8019a0a --- /dev/null +++ b/src/notzed.vulkan.test/gen/sdf.vert @@ -0,0 +1,9 @@ +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec4 pos; + +void main() { + gl_Position = pos; +} diff --git a/src/notzed.vulkan/gen/generate-vulkan b/src/notzed.vulkan/gen/generate-vulkan index e1c7d1a..238797e 100755 --- a/src/notzed.vulkan/gen/generate-vulkan +++ b/src/notzed.vulkan/gen/generate-vulkan @@ -208,6 +208,11 @@ foreach my $s (values %{$api->{commands}}) { } } +if (0) { + analyseAccessors($api); + exit 1; +} + if (0) { open(my $f, '>', 'types.pm'); print $f Dumper($commandTypes, $structTypes); @@ -221,7 +226,14 @@ if (0) { die; } -exportEnums($vk, $api, 'VkConstants'); +if (0) { + open(my $f, '>', 'vk.pm'); + print $f Dumper($vk); + close $f; + die; +} + +exportVulkan($vk, $api, $structTypes); # dump out the extension function-pointer tables { @@ -299,6 +311,114 @@ exit 0; # ###################################################################### # +sub formatStructLayout { + my $types = shift; + my $s = shift; + my $offset = 0; + my @fields = (); + + # This doens't need to worry about overrides + + if ($s->{category} eq 'struct') { + foreach my $m (@{$s->{items}}) { + my $type = $types->{$m->{deref}}; + my $diff = $m->{bitOffset} - $offset; + + push @fields, "MemoryLayout.paddingLayout($diff)" if $diff; + + if ($type) { + my $v = buildVars($s, $m, $type); + + push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */"; + $offset = $m->{bitOffset} + $m->{bitSize}; + } else { + push @fields, "/* Missing: $m->{deref} $m->{name} */"; + } + } + } else { + foreach my $m (@{$s->{items}}) { + my $type = $types->{$m->{deref}}; + + if ($type) { + my $v = buildVars($s, $m, $type); + + push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */"; + $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset; + } else { + push @fields, "/* Missing: $m->{deref} $m->{name} */"; + } + } + } + + my $diff = $s->{bitSize} - $offset; + + push @fields, "MemoryLayout.paddingLayout($diff)" if $diff; + + return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")"; +} + +# Experiment: see if sharing varhandles would be of any benefit +# - analyse all pointer/int fields for cross-overs +# for vulkan 1.3: +# Total fields: 3370 +# Unique fields: 368 +# so very significant savings possible +sub analyseAccessors { + my $api = shift; + my %handles; + my $total; + my %lookat; + + map { $lookat{$_} = 1 } qw(Memory.POINTER Memory.BYTE Memory.SHORT Memory.INT Memory.LONG Memory.FLOAT Memory.DOUBLE); + + foreach my $s (values %{$api->{types}}) { + my $override = $structTypes->{overrides}->{$s->{name}}; + + next if $s->{alias}; + next if $override->{ignore}; + + foreach my $m (@{$s->{items}}) { + my $deref = $m->{deref}; + my $type = $structTypes->{types}->{$deref}; + my $v = buildVars($s, $m, $type); + my $layout = code::formatTemplate($v->{layout}, $v); + my $index = $m->{bitOffset} / 8; + + die if ($m->{bitoffset} & ($m->{bitSize}-1)); + + if ($lookat{$layout}) { + $index = $m->{bitOffset} / $m->{bitSize}; + } + + my $k = sprintf "$layout \@ %03d", $index; + + $handles{$k}++; + $total++; + } + } + + print "Other unique handles =\n"; + foreach my $h (sort keys %handles) { + $h =~ m/^(.*) \@/; + my $x = $lookat{$1}; + if (!$lookat{$1}) { + printf " %5d $h\n", $handles{$h}; + } + } + print "Unique handles of interest =\n"; + foreach my $h (sort keys %handles) { + $h =~ m/^(.*) \@/; + if ($lookat{$1}) { + printf " %5d $h\n", $handles{$h}; + } + } + my @keys = keys %handles; + print "Total fields: $total\n"; + print "Unique fields: $#keys\n"; +} + +# ###################################################################### # + sub loadTypes { my $api = shift; my $file = shift; @@ -425,22 +545,22 @@ sub uniq { return grep { !$seen{$_}++ } @_; } -sub exportEnums { +# generate Vulkan.java +sub exportVulkan { my $vk = shift; my $api = shift; - my $name = shift; + my $structTypes = shift; my $seen = {}; + my $template = $structTypes->{templates}->{Vulkan}; - my $f = openOutput($sys, $name); + my @constants = (); + my @defines = (); - print $f "package vulkan;\npublic interface VkConstants {\n"; - - # special case for api constants # special case for api constants { my $s = $api->{data}->{'API Constants'}; - print $f "\n\t// API Constants\n"; + push @constants, "// API Constants\n"; foreach my $m (@{$s->{items}}) { next if defined($m->{alias}); @@ -452,7 +572,16 @@ sub exportEnums { # convert to java $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/)); - print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n"; + push @constants,"public final static $i->{type} $m->{name} = $v$i->{suffix};"; + } + } + + # include any defines we have a template for + foreach my $k (sort keys %{$api->{defines}}) { + if ($template->{$k}) { + push @defines, $template->{$k}; + } else { + print "Ignored: $k\n"; } } @@ -463,7 +592,8 @@ sub exportEnums { next if $s->{alias}; - print $f "\n\t// $s->{name} $type\n"; + push @constants, ""; + push @constants, "// $s->{name} $type"; foreach my $m (@{$s->{items}}) { next if defined($m->{alias}); @@ -474,12 +604,21 @@ sub exportEnums { $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos}); die Dumper("Ca't work out value", $m, $s) if !defined($v); - print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n"; + push @constants, "public final static $i->{type} $m->{name} = $v$i->{suffix};"; } } - print $f "}\n"; - closeOutput($sys, $name, $f); + my $v = { + package => $sys->{package}, + defines => join("\n\t", @defines), + constants => join("\n\t", @constants), + }; + + my $f = openOutput($sys, 'Vulkan'); + + print $f code::formatTemplateStream($template->{class}, $v); + + closeOutput($sys, 'Vulkan', $f); } # ###################################################################### # @@ -615,7 +754,7 @@ sub analyseFields { if ($s->{category} =~ m/struct|union/on) { if ($m->{altlen}) { if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) { - $m->{length} = $1.'VkConstants.'.$2.$3; + $m->{length} = $1.'Vulkan.'.$2.$3; } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) { my $len = $index->{$2}; if (defined $len) { @@ -1101,7 +1240,7 @@ sub collectFunctionInfo { $info->{'native-result-define'} = 'int result$;'; $info->{'native-result-assign'} = 'result$ = (int)'; - $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')'; + $info->{'result-test'} = 'if ('.join("||", map { '(result$ == Vulkan.'.$_.')' } @codes).')'; $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);'; if ($#codes > 0 && $info->{'java-result'} eq 'void') { diff --git a/src/notzed.vulkan/gen/struct-types.api b/src/notzed.vulkan/gen/struct-types.api index 96a49f0..48808ce 100644 --- a/src/notzed.vulkan/gen/struct-types.api +++ b/src/notzed.vulkan/gen/struct-types.api @@ -40,13 +40,13 @@ code value { # Initialise the sType field if it has one, also include sub- init eval {{ if ($tempname =~ m/write/) { - my $init = "{name}\$VH.set(self\$.segment, VkConstants.{values});\n"; + my $init = "{name}\$VH.set(self\$.segment, Vulkan.{values});\n"; foreach my $x (@{$s->{items}}) { if ($x->{deref} eq 'struct') { my $y = $api->{types}->{$x->{baseType}}; if ($#{$y->{items}} >= 0 && $y->{items}->[0]->{values}) { my $z = $y->{items}->[0]; - $init .= "self\$.get$x->{Name}().set$z->{Name}(VkConstants.$z->{values});\n"; + $init .= "self\$.get$x->{Name}().set$z->{Name}(Vulkan.$z->{values});\n"; } } } @@ -58,13 +58,13 @@ code value { init-array eval {{ if ($tempname =~ m/write.*array/n) { - my $init = "{name}\$AH.set(self\$.segment, i, VkConstants.{values});\n"; + my $init = "{name}\$AH.set(self\$.segment, i, Vulkan.{values});\n"; foreach my $x (@{$s->{items}}) { if ($x->{deref} eq 'struct') { my $y = $api->{types}->{$x->{baseType}}; if ($#{$y->{items}} >= 0 && $y->{items}->[0]->{values}) { my $z = $y->{items}->[0]; - $init .= "self\$.get$x->{Name}AtIndex(i).set$z->{Name}(VkConstants.$z->{values});\n"; + $init .= "self\$.get$x->{Name}AtIndex(i).set$z->{Name}(Vulkan.$z->{values});\n"; } } } @@ -76,6 +76,7 @@ code value { }} # for complex constructors + #setall-arg {{ {type} {name} }} setall-arg {{ {type} {name} }} setall {{ self$.set{Name}({name}); }} } @@ -210,6 +211,26 @@ code value-implied value { # ###################################################################### # +code Vulkan { + class {{ + package {package}; + public class Vulkan { + + public static int VK_MAKE_API_VERSION(int variant, int major, int minor, int patch) { + return (variant << 29) | (major << 22) | (minor << 12) | patch; + } + + {defines} + + {constants} + } + }} + VK_API_VERSION_1_0 {{ public final static int VK_API_VERSION_1_0 = VK_MAKE_API_VERSION(0, 1, 0, 0); }} + VK_API_VERSION_1_1 {{ public final static int VK_API_VERSION_1_1 = VK_MAKE_API_VERSION(0, 1, 1, 0); }} + VK_API_VERSION_1_2 {{ public final static int VK_API_VERSION_1_2 = VK_MAKE_API_VERSION(0, 1, 2, 0); }} + VK_API_VERSION_1_3 {{ public final static int VK_API_VERSION_1_3 = VK_MAKE_API_VERSION(0, 1, 3, 0); }} +} + code dispatch { class {{ // template: dispatch:class @@ -896,6 +917,13 @@ override structs { VkAllocationCallbacks ignore; + # We want 'set(all fields) for these types + #VkOffset2D template=struct-readwrite-all; + #VkOffset3D template=struct-readwrite-all-array; + #VkExtent2D template=struct-readwrite-all; + #VkExtent3D template=struct-readwrite-all; + #VkRect2D template=struct-readwrite-all; + # Override default read/write VkDebugUtilsMessengerCallbackDataEXT template=struct-readonly; VkDebugUtilsLabelEXT template=struct-readonly-array; diff --git a/src/notzed.vulkan/gen/vulkan.pm b/src/notzed.vulkan/gen/vulkan.pm index a337d4c..795b3b8 100644 --- a/src/notzed.vulkan/gen/vulkan.pm +++ b/src/notzed.vulkan/gen/vulkan.pm @@ -73,24 +73,21 @@ sub buildRequirement { # add a couple of constants that the api's dont reference push @{$outconst->{items}}, grep { $_->{name} =~ m/VK_UUID_SIZE/ } @{$allconst->{items}}; - #print " $req->{comment}\n"; - #print Dumper($req->{types}); + # Find included types in this requirement foreach my $c (@{$req->{commands}}, @{$req->{types}}) { my $d = $vk->{data}->{$c}; - #print Dumper({ d=> $d, c => $c }); - - # what about aliases? if (defined $d) { if ($d->{category} eq 'enum' && !defined($d->{alias})) { $d = { %$d }; $d->{items} = [ @{$d->{items}} ] if defined($d->{items}); } $data->{$c} = $d; - - #print "Alias: $d->{alias}\n" if defined($d->{alias}); } else { - print "Ignored: ".Dumper($c); + $data->{$c} = { + name => $c, + category => 'define', + }; } } foreach my $c (@{$req->{enums}}) { @@ -173,6 +170,7 @@ sub buildFeatures { my $enums = {}; my $bitmasks = {}; my $funcpointers = {}; + my $defines = {}; foreach my $t (keys %{$data}) { my $v = $data->{$t}; @@ -182,6 +180,7 @@ sub buildFeatures { $enums->{$v->{name}} = $v if $v->{category} eq 'enum'; $bitmasks->{$v->{name}} = $v if $v->{category} eq 'bitmask'; $funcpointers->{$v->{name}} = $v if $v->{category} eq 'funcpointer'; + $defines->{$v->{name}} = $v if $v->{category} eq 'define'; } # link enums to their type(s) @@ -221,6 +220,7 @@ sub buildFeatures { funcpointers => $funcpointers, enums => $enums, bitmasks => $bitmasks, + defines => $defines, }; # create sizes for every struct of interest @@ -470,10 +470,12 @@ sub loadRegistry { } } elsif ($ya->{category} eq 'enum') { $data->{$ya->{name}} = $ya; - } elsif ($ya->{requires} || $ya->{name} eq 'int') { - # ?? wtf to do with this + } elsif ($ya->{requires} eq 'vk_platform' || $ya->{name} eq 'int') { + # These are just primitive types, not sure what to do with them, could auto-map them to java i suppose $ya->{category} = 'platform'; $data->{$ya->{name}} = $ya; + } else { + #noisy print "Unhandled: $ya->{name}\n"; } } } elsif ($xt eq 'enums') { diff --git a/src/notzed.xlib/gen/xlib.api b/src/notzed.xlib/gen/xlib.api index 1cd19b5..45200f3 100644 --- a/src/notzed.xlib/gen/xlib.api +++ b/src/notzed.xlib/gen/xlib.api @@ -9,6 +9,9 @@ struct default=all access=rw rename=s/^_// field:rename=studly-caps { xid rename=XID; } +union default=all access=rw rename=s/^_// field:rename=studly-caps { +} + struct _XPrivDisplay { screens array array-size=nscreens access=r; } @@ -30,14 +33,23 @@ library XLib { define:xlib; func:XCreateColormap; func:XCreateWindow; + func:XDestroyWindow; func:XFlush; func:XGetVisualInfo; func:XInitThreads; func:XInternAtom; func:XMapWindow; func:XOpenDisplay; + func:XCloseDisplay; func:XSelectInput; + func:XSetWMProtocols; + + func:XPending; + func:XNextEvent; + func:XWindowEvent; + func:XCheckWindowEvent; + # #define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen) # #define RootWindow(dpy, scr) (ScreenOfDisplay(dpy,scr)->root) # #define ScreenOfDisplay(dpy, scr)(&((_XPrivDisplay)(dpy))->screens[scr]) @@ -60,4 +72,6 @@ library XLib { define xlib xlib.h { /Pixel$|^Input|^CW|Mask$|^Alloc/ include; + /KeyPress|KeyRelease|ButtonPress|ButtonRelease|MotionNotify|EnterNotify|LeaveNotify|FocusIn|FocusOut|KeymapNotify|Expose|GraphicsExpose|NoExpose|VisibilityNotify|CreateNotify|DestroyNotify|UnmapNotify|MapNotify|MapRequest|ReparentNotify|ConfigureNotify|ConfigureRequest|GravityNotify|ResizeRequest|CirculateNotify|CirculateRequest|PropertyNotify|SelectionClear|SelectionRequest|SelectionNotify|ColormapNotify|ClientMessage|MappingNotify|GenericEvent/ include; + } -- 2.39.2