diff --git a/graphics/vulkan/build.gradle b/graphics/vulkan/build.gradle new file mode 100644 index 0000000..399589e --- /dev/null +++ b/graphics/vulkan/build.gradle @@ -0,0 +1,93 @@ +import org.gradle.internal.os.OperatingSystem + +plugins { + id 'java' + id 'io.freefair.lombok' version "${pluginLombok}" +} + +// Determine LWJGL native stuff +switch (OperatingSystem.current()) { + case OperatingSystem.LINUX: + project.dependencyLwjglNatives = "natives-linux" + def osArch = System.getProperty("os.arch") + if (osArch.startsWith("arm") || osArch.startsWith("aarch64")) { + project.dependencyLwjglNatives += osArch.contains("64") || osArch.startsWith("armv8") ? "-arm64" : "-arm32" + } else if (osArch.startsWith("ppc")) { + project.dependencyLwjglNatives += "-ppc64le" + } else if (osArch.startsWith("riscv")) { + project.dependencyLwjglNatives += "-riscv64" + } + break + case OperatingSystem.MAC_OS: + project.dependencyLwjglNatives = System.getProperty("os.arch").startsWith("aarch64") ? "natives-macos-arm64" : "natives-macos" + break + case OperatingSystem.WINDOWS: + def osArch = System.getProperty("os.arch") + project.dependencyLwjglNatives = osArch.contains("64") + ? "natives-windows${osArch.startsWith("aarch64") ? "-arm64" : ""}" + : "natives-windows-x86" + break +} + +dependencies { + // -> Runtime <- + // Lombok + compileOnly 'org.projectlombok:lombok:' + project.dependencyLombok + annotationProcessor 'org.projectlombok:lombok:' + project.dependencyLombok + + // JetBrains Annotations + compileOnly 'org.jetbrains:annotations:' + project.dependencyJetbrainsAnnotations + + // LWJGL + implementation platform("org.lwjgl:lwjgl-bom:${dependencyLwjgl}") + implementation "org.lwjgl:lwjgl" + implementation "org.lwjgl:lwjgl-bgfx" + implementation "org.lwjgl:lwjgl-egl" + implementation "org.lwjgl:lwjgl-glfw" + implementation "org.lwjgl:lwjgl-ktx" + implementation "org.lwjgl:lwjgl-shaderc" + implementation "org.lwjgl:lwjgl-sse" + implementation "org.lwjgl:lwjgl-vma" + implementation "org.lwjgl:lwjgl-vulkan" + runtimeOnly "org.lwjgl:lwjgl::${dependencyLwjglNatives}" + runtimeOnly "org.lwjgl:lwjgl-bgfx::${dependencyLwjglNatives}" + runtimeOnly "org.lwjgl:lwjgl-glfw::${dependencyLwjglNatives}" + runtimeOnly "org.lwjgl:lwjgl-ktx::${dependencyLwjglNatives}" + runtimeOnly "org.lwjgl:lwjgl-shaderc::${dependencyLwjglNatives}" + runtimeOnly "org.lwjgl:lwjgl-sse::${dependencyLwjglNatives}" + runtimeOnly "org.lwjgl:lwjgl-vma::${dependencyLwjglNatives}" + if (project.dependencyLwjglNatives == "natives-macos" || project.dependencyLwjglNatives == "natives-macos-arm64") runtimeOnly "org.lwjgl:lwjgl-vulkan::${dependencyLwjglNatives}" + + // -> Testing <- + // Jetbrains Annotations + testCompileOnly 'org.jetbrains:annotations:' + project.dependencyJetbrainsAnnotations + + // JUnit + testImplementation platform('org.junit:junit-bom:5.' + project.dependencyJunit) + testImplementation 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // jOOR + testImplementation 'org.jooq:joor:' + project.dependencyJoor + + // -> Project <- + implementation project(":base") + implementation project(":graphics") +} + +javadoc.options { + setMemberLevel(JavadocMemberLevel.PUBLIC) + setOverview("src/main/javadoc/overview.html") + setLocale("en_US") + setJFlags([ + // Force Javadoc to use English translations + "-Duser.language=en_US" + ]) +} + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} diff --git a/graphics/vulkan/gradle b/graphics/vulkan/gradle new file mode 120000 index 0000000..1ce6c4c --- /dev/null +++ b/graphics/vulkan/gradle @@ -0,0 +1 @@ +../../gradle \ No newline at end of file diff --git a/graphics/vulkan/gradlew b/graphics/vulkan/gradlew new file mode 120000 index 0000000..343e0d2 --- /dev/null +++ b/graphics/vulkan/gradlew @@ -0,0 +1 @@ +../../gradlew \ No newline at end of file diff --git a/graphics/vulkan/gradlew.bat b/graphics/vulkan/gradlew.bat new file mode 120000 index 0000000..cb5a946 --- /dev/null +++ b/graphics/vulkan/gradlew.bat @@ -0,0 +1 @@ +../../gradlew.bat \ No newline at end of file diff --git a/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/VulkanManagement.java b/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/VulkanManagement.java new file mode 100644 index 0000000..ddd4241 --- /dev/null +++ b/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/VulkanManagement.java @@ -0,0 +1,34 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.vulkan; + +import de.staropensource.sosengine.base.classes.Vec2i; +import de.staropensource.sosengine.graphics.classes.ApiManagementClass; +import de.staropensource.sosengine.graphics.classes.Window; +import org.jetbrains.annotations.NotNull; + +public class VulkanManagement implements ApiManagementClass { + /** {@inheritDoc} */ + @NotNull + @Override + public Window createWindow(String title, Vec2i size) { + return null; + } +} diff --git a/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/VulkanSubsystem.java b/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/VulkanSubsystem.java new file mode 100644 index 0000000..5e74be5 --- /dev/null +++ b/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/VulkanSubsystem.java @@ -0,0 +1,162 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.vulkan; + +import de.staropensource.sosengine.base.annotations.EventListener; +import de.staropensource.sosengine.base.classes.EventPriority; +import de.staropensource.sosengine.base.logging.LoggerInstance; +import de.staropensource.sosengine.base.types.LogIssuer; +import de.staropensource.sosengine.base.utility.Miscellaneous; +import de.staropensource.sosengine.graphics.GraphicsSubsystem; +import de.staropensource.sosengine.graphics.classes.ApiMainClass; +import de.staropensource.sosengine.graphics.classes.ApiManagementClass; +import de.staropensource.sosengine.graphics.vulkan.events.GraphicsErrorEvent; +import lombok.Getter; +import org.lwjgl.glfw.GLFWErrorCallback; + +import static org.lwjgl.glfw.GLFW.*; + +/** + * The main object for the Vulkan Graphics API. + * + * @since 1-alpha0 + */ +@SuppressWarnings({ "unused", "JavadocDeclaration", "JavadocBlankLines" }) +public final class VulkanSubsystem implements ApiMainClass { + /** + * Instance. + * + * @since 1-alpha0 + * + * -- GETTER -- + * Returns the {@link VulkanSubsystem} instance. + * + * @return {@link VulkanSubsystem} instance unless uninitialized + * @since 1-alpha0 + */ + @Getter + private static VulkanSubsystem instance = null; + + /** + * Logger instance. + * + * @see LoggerInstance + * @since 1-alpha0 + */ + private final LoggerInstance logger = new LoggerInstance(new LogIssuer(getClass())); + + /** + * The Graphics API management class. + * + * @see ApiManagementClass + * @since 1-alpha0 + * + * -- GETTER -- + * {@inheritDoc} + */ + @Getter + private ApiManagementClass management; + + /** + * Constructor. + * + * @since 1-alpha0 + */ + public VulkanSubsystem() { + // Check if subsystem has already initialized + if (instance == null) + instance = this; + else { + instance.logger.crash("The subsystem tried to initialize twice"); + return; + } + + // Warn about instability + logger.warn("The Vulkan Graphics API is unfinished. Trying to initialize it will lead to an engine crash."); + + // Register Graphics API + GraphicsSubsystem.getInstance().registerGraphicsApi(this); + + logger.info("Initialized subsystem"); + } + + /** {@inheritDoc} */ + @Override + public void initializeApi() { + logger.verb("Initializing Graphics API"); + + long initTime = Miscellaneous.measureExecutionTime(() -> { + logger.crash("The Vulkan Graphics API subsystem is unfinished."); + + // Set error callback + try (GLFWErrorCallback errorCallback = GLFWErrorCallback.create(new GraphicsErrorEvent())) { + errorCallback.set(); + } + + // Initialize GLFW + if (!glfwInit()) + logger.crash("Unable to initialize GLFW"); + }); + + logger.info("Initialized Graphics API in " + initTime + "ms"); + } + + /** {@inheritDoc} */ + @Override + public String getApiName() { + return "Vulkan"; + } + + /** {@inheritDoc} */ + @Override + public boolean isCompatible() { + return false; + } + + /** + * Called when a graphics error occurs. This method just logs the error and returns. + * + * @param error graphics error + * @since 1-alpha0 + */ + @EventListener(event = GraphicsErrorEvent.class, priority = EventPriority.EXTREMELY_IMPORTANT) + public static void onGraphicsError(String error) { + instance.logger.error("An error occurred: " + error); + } + + /** + * Shuts the graphics subsystem down. + * + * @since 1-alpha0 + */ + public static void shutdownApi() { + LoggerInstance logger = instance.logger; + logger.verb("Shutting down"); + + @SuppressWarnings("resource") + long shutdownTime = Miscellaneous.measureExecutionTime(() -> { + glfwTerminate(); + //noinspection DataFlowIssue + glfwSetErrorCallback(null).free(); + }); + + logger.info("Shut down in " + shutdownTime + "ms"); + } +} diff --git a/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/events/GraphicsErrorEvent.java b/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/events/GraphicsErrorEvent.java new file mode 100644 index 0000000..dd0fef0 --- /dev/null +++ b/graphics/vulkan/src/main/java/de/staropensource/sosengine/graphics/vulkan/events/GraphicsErrorEvent.java @@ -0,0 +1,42 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.graphics.vulkan.events; + +import org.lwjgl.glfw.GLFWErrorCallbackI; + +/** + * Called when a graphics error occurs. + * + * @since 1-alpha0 + */ +@SuppressWarnings({ "unused" }) +public class GraphicsErrorEvent extends de.staropensource.sosengine.graphics.events.GraphicsErrorEvent implements GLFWErrorCallbackI { + /** + * Constructor. + */ + public GraphicsErrorEvent() {} + + + /** {@inheritDoc} */ + @Override + public void invoke(int error, long description) { + callEvent(description + " (" + error + ")"); + } +} diff --git a/settings.gradle b/settings.gradle index a43ff67..fe8f07b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,5 @@ rootProject.name = 'sosengine' include 'base' include 'slf4j-compat' include 'graphics' +include 'graphics:vulkan' include 'testapp' diff --git a/testapp/build.gradle b/testapp/build.gradle index 16ae7c3..685f99e 100644 --- a/testapp/build.gradle +++ b/testapp/build.gradle @@ -18,6 +18,7 @@ dependencies { implementation project(":base") implementation project(":slf4j-compat") implementation project(":graphics") + implementation project(":graphics:vulkan") } javadoc.options { diff --git a/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java b/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java index 43e51d0..3476c5a 100644 --- a/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java +++ b/testapp/src/main/java/de/staropensource/sosengine/testapp/Main.java @@ -26,6 +26,7 @@ import de.staropensource.sosengine.base.types.LogIssuer; import de.staropensource.sosengine.graphics.GraphicsSubsystem; import de.staropensource.sosengine.graphics.classes.ApiMainClass; import de.staropensource.sosengine.graphics.classes.ApiManagementClass; +import de.staropensource.sosengine.graphics.vulkan.VulkanSubsystem; import de.staropensource.sosengine.slf4j_compat.Slf4jCompatibilitySubsystem; import lombok.Getter; import lombok.SneakyThrows; @@ -101,6 +102,7 @@ public class Main { // Initialize subsystems new Slf4jCompatibilitySubsystem(); new GraphicsSubsystem(); + new VulkanSubsystem(); // Choose Graphics API to use if (!GraphicsSubsystem.getInstance().setGraphicsApi()) {