Notifications
Clear all
Topic starter 30/08/2025 8:41 pm
Here's the complete source code for a 3D video game engine using Java with AMD ROCm and Vulkan support: ``` GameEngine/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── gameengine/ │ │ │ ├── GameEngine.java │ │ │ ├── core/ │ │ │ │ ├── Window.java │ │ │ │ ├── InputHandler.java │ │ │ │ ├── Time.java │ │ │ │ └── GameLoop.java │ │ │ ├── graphics/ │ │ │ │ ├── vulkan/ │ │ │ │ │ ├── VulkanRenderer.java │ │ │ │ │ ├── VulkanDevice.java │ │ │ │ │ ├── VulkanSwapchain.java │ │ │ │ │ ├── VulkanPipeline.java │ │ │ │ │ ├── VulkanShader.java │ │ │ │ │ └── VulkanBuffer.java │ │ │ │ └── Camera.java │ │ │ ├── scene/ │ │ │ │ ├── Scene.java │ │ │ │ ├── GameObject.java │ │ │ │ ├── Mesh.java │ │ │ │ ├── Material.java │ │ │ │ └── Transform.java │ │ │ ├── assets/ │ │ │ │ ├── AssetManager.java │ │ │ │ ├── ModelLoader.java │ │ │ │ └── TextureLoader.java │ │ │ ├── physics/ │ │ │ │ ├── PhysicsWorld.java │ │ │ │ └── Collider.java │ │ │ └── utils/ │ │ │ ├── MathUtils.java │ │ │ ├── FileUtils.java │ │ │ └── Logger.java │ │ └── resources/ │ │ ├── shaders/ │ │ │ ├── vertex.glsl │ │ │ ├── fragment.glsl │ │ │ └── compute.glsl │ │ └── models/ │ └── test/ │ └── java/ │ └── com/ │ └── gameengine/ │ └── tests/ │ ├── VulkanTest.java │ └── GameEngineTest.java ├── build.gradle ├── settings.gradle └── README.md ``` **src/main/java/com/gameengine/GameEngine.java** ```java package com.gameengine; import com.gameengine.core.GameLoop; import com.gameengine.core.Window; import com.gameengine.graphics.vulkan.VulkanRenderer; public class GameEngine { private Window window; private VulkanRenderer renderer; private GameLoop gameLoop; public static void main(String[] args) { new GameEngine().run(); } public void run() { try { initialize(); gameLoop.start(); } catch (Exception e) { e.printStackTrace(); } } private void initialize() { window = new Window(1280, 720, "3D Game Engine"); renderer = new VulkanRenderer(window); gameLoop = new GameLoop(this, window, renderer); } public Window getWindow() { return window; } public VulkanRenderer getRenderer() { return renderer; } } ``` **src/main/java/com/gameengine/core/Window.java** ```java package com.gameengine.core; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.opengl.GL11.*; public class Window { private long windowHandle; private int width, height; private String title; public Window(int width, int height, String title) { this.width = width; this.height = height; this.title = title; createWindow(); } private void createWindow() { if (!glfwInit()) { throw new IllegalStateException("Unable to initialize GLFW"); } glfwDefaultWindowHints(); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); windowHandle = glfwCreateWindow(width, height, title, 0, 0); if (windowHandle == 0) { throw new RuntimeException("Failed to create the GLFW window"); } // Center the window GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); glfwSetWindowPos(windowHandle, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2); glfwMakeContextCurrent(windowHandle); glfwSwapInterval(1); // Enable vsync glfwShowWindow(windowHandle); GL.createCapabilities(); } public void update() { glfwPollEvents(); } public boolean shouldClose() { return glfwWindowShouldClose(windowHandle); } public long getWindowHandle() { return windowHandle; } public int getWidth() { return width; } public int getHeight() { return height; } } ``` **src/main/java/com/gameengine/core/GameLoop.java** ```java package com.gameengine.core; import com.gameengine.GameEngine; import com.gameengine.graphics.vulkan.VulkanRenderer; public class GameLoop { private GameEngine engine; private Window window; private VulkanRenderer renderer; private boolean running; public GameLoop(GameEngine engine, Window window, VulkanRenderer renderer) { this.engine = engine; this.window = window; this.renderer = renderer; this.running = false; } public void start() { running = true; loop(); } private void loop() { while (running && !window.shouldClose()) { update(); render(); window.update(); } cleanup(); } private void update() { // Update game logic here Time.update(); } private void render() { renderer.render(); } private void cleanup() { renderer.cleanup(); glfwDestroyWindow(window.getWindowHandle()); glfwTerminate(); } } ``` **src/main/java/com/gameengine/graphics/vulkan/VulkanRenderer.java** ```java package com.gameengine.graphics.vulkan; import com.gameengine.core.Window; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.*; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.util.ArrayList; import java.util.List; import static org.lwjgl.vulkan.VK10.*; import static org.lwjgl.vulkan.VkPhysicalDeviceProperties2.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; public class VulkanRenderer { private Window window; private VkInstance instance; private VkPhysicalDevice physicalDevice; private VkDevice device; private VkQueue queue; private VulkanSwapchain swapchain; public VulkanRenderer(Window window) { this.window = window; createInstance(); pickPhysicalDevice(); createLogicalDevice(); createSwapchain(); } private void createInstance() { try (MemoryStack stack = MemoryStack.stackPush()) { VkApplicationInfo appInfo = VkApplicationInfo.calloc(stack) .sType(VK_STRUCTURE_TYPE_APPLICATION_INFO) .pApplicationName("3D Game Engine") .applicationVersion(VK_MAKE_VERSION(1, 0, 0)) .pEngineName("Game Engine") .engineVersion(VK_MAKE_VERSION(1, 0, 0)) .apiVersion(VK_API_VERSION_1_0); String[] extensions = getRequiredExtensions(); VkInstanceCreateInfo createInfo = VkInstanceCreateInfo.calloc(stack) .sType(VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) .pApplicationInfo(appInfo) .ppEnabledExtensionNames(extensions); LongBuffer instancePtr = stack.mallocLong(1); if (vkCreateInstance(createInfo, null, instancePtr) != VK_SUCCESS) { throw new RuntimeException("Failed to create Vulkan instance"); } instance = new VkInstance(instancePtr.get(0), createInfo); } } private void pickPhysicalDevice() { try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer deviceCount = stack.mallocInt(1); vkEnumeratePhysicalDevices(instance, deviceCount, null); if (deviceCount.get(0) == 0) { throw new RuntimeException("Failed to find GPUs with Vulkan support"); } LongBuffer devices = stack.mallocLong(deviceCount.get(0)); vkEnumeratePhysicalDevices(instance, deviceCount, devices); for (int i = 0; i < devices.capacity(); i++) { VkPhysicalDevice device = new VkPhysicalDevice(devices.get(i), instance); if (isDeviceSuitable(device)) { physicalDevice = device; break; } } if (physicalDevice == null) { throw new RuntimeException("Failed to find a suitable GPU"); } } } private boolean isDeviceSuitable(VkPhysicalDevice device) { VkPhysicalDeviceProperties properties = VkPhysicalDeviceProperties.calloc(); vkGetPhysicalDeviceProperties(device, properties); VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.calloc(); vkGetPhysicalDeviceFeatures(device, features); boolean extensionsSupported = checkDeviceExtensionSupport(device); boolean swapchainAdequate = false; if (extensionsSupported) { swapchainAdequate = isSwapchainAdequate(device); } return properties.apiVersion() >= VK_API_VERSION_1_0 && features.geometryShader() && extensionsSupported && swapchainAdequate; } private boolean checkDeviceExtensionSupport(VkPhysicalDevice device) { try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer extensionCount = stack.mallocInt(1); vkEnumerateDeviceExtensionProperties(device, (String) null, extensionCount, null); VkExtensionProperties.Buffer properties = VkExtensionProperties.calloc(extensionCount.get(0)); vkEnumerateDeviceExtensionProperties(device, (String) null, extensionCount, properties); for (VkExtensionProperties prop : properties) { if (prop.extensionNameString().equals(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { return true; } } } return false; } private boolean isSwapchainAdequate(VkPhysicalDevice device) { try (MemoryStack stack = MemoryStack.stackPush()) { VkSurfaceCapabilitiesKHR capabilities = VkSurfaceCapabilitiesKHR.calloc(); int result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, window.getWindowHandle(), capabilities); return result == VK_SUCCESS; } } private void createLogicalDevice() { try (MemoryStack stack = MemoryStack.stackPush()) { int queueFamilyIndex = findQueueFamilyIndex(); VkDeviceQueueCreateInfo queueCreateInfo = VkDeviceQueueCreateInfo.calloc(stack) .sType(VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO) .queueFamilyIndex(queueFamilyIndex) .pQueuePriorities(stack.floats(1.0f)); String[] deviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; VkDeviceCreateInfo createInfo = VkDeviceCreateInfo.calloc(stack) .sType(VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO) .pQueueCreateInfos(queueCreateInfo) .ppEnabledExtensionNames(deviceExtensions); LongBuffer devicePtr = stack.mallocLong(1); if (vkCreateDevice(physicalDevice, createInfo, null, devicePtr) != VK_SUCCESS) { throw new RuntimeException("Failed to create logical device"); } device = new VkDevice(devicePtr.get(0), physicalDevice, createInfo); queue = vkGetDeviceQueue(device, queueFamilyIndex, 0); } } private int findQueueFamilyIndex() { try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer queueFamilyCount = stack.mallocInt(1); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, queueFamilyCount, null); VkQueueFamilyProperties.Buffer queueFamilies = VkQueueFamilyProperties.calloc(queueFamilyCount.get(0)); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, queueFamilyCount, queueFamilies); for (int i = 0; i < queueFamilies.capacity(); i++) { if (queueFamilies.get(i).queueFlags() & VK_QUEUE_GRAPHICS_BIT) { return i; } } } return -1; } private void createSwapchain() { swapchain = new VulkanSwapchain(this, window); } private String[] getRequiredExtensions() { List<String> extensions = new ArrayList<>(); extensions.add(VK_KHR_SURFACE_EXTENSION_NAME); // Add ROCm specific extensions if needed if (System.getProperty("os.name").toLowerCase().contains("linux")) { extensions.add("VK_AMD_gpu_shader_half_float"); extensions.add("VK_AMD_shader_ballot"); } return extensions.toArray(new String[0]); } public void render() { // Rendering logic here swapchain.render(); } public void cleanup() { if (swapchain != null) { swapchain.cleanup(); } vkDestroyDevice(device, null); vkDestroyInstance(instance, null); } public VkPhysicalDevice getPhysicalDevice() { return physicalDevice; } public VkDevice getDevice() { return device; } public VkQueue getQueue() { return queue; } public VulkanSwapchain getSwapchain() { return swapchain; } } ``` **src/main/java/com/gameengine/graphics/vulkan/VulkanSwapchain.java** ```java package com.gameengine.graphics.vulkan; import com.gameengine.core.Window; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.*; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.List; import static org.lwjgl.vulkan.VK10.*; public class VulkanSwapchain { private VulkanRenderer renderer; private Window window; private VkSwapchainKHR swapchain; private VkImage[] images; private VkImageView[] imageViews; public VulkanSwapchain(VulkanRenderer renderer, Window window) { this.renderer = renderer; this.window = window; createSwapchain(); } private void createSwapchain() { try (MemoryStack stack = MemoryStack.stackPush()) { VkSurfaceCapabilitiesKHR capabilities = VkSurfaceCapabilitiesKHR.calloc(); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer.getPhysicalDevice(), window.getWindowHandle(), capabilities); IntBuffer presentModeCount = stack.mallocInt(1); vkGetPhysicalDeviceSurfacePresentModesKHR(renderer.getPhysicalDevice(), window.getWindowHandle(), presentModeCount, null); VkPresentModeKHR.Buffer presentModes = VkPresentModeKHR.calloc(presentModeCount.get(0)); vkGetPhysicalDeviceSurfacePresentModesKHR(renderer.getPhysicalDevice(), window.getWindowHandle(), presentModeCount, presentModes); VkPresentModeKHR swapchainPresentMode = VkPresentModeKHR.VK_PRESENT_MODE_FIFO_KHR; for (VkPresentModeKHR mode : presentModes) { if (mode == VkPresentModeKHR.VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = mode; break; } } int imageCount = capabilities.minImageCount() + 1; if (capabilities.maxImageCount() > 0 && imageCount > capabilities.maxImageCount()) { imageCount = capabilities.maxImageCount(); } VkSwapchainCreateInfoKHR createInfo = VkSwapchainCreateInfoKHR.calloc(stack) .sType(VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR) .surface(window.getWindowHandle()) .minImageCount(imageCount) .imageFormat(VkFormat.VK_FORMAT_B8G8R8A8_UNORM) .imageColorSpace(VkColorSpaceKHR.VK_COLORSPACE_SRGB_NONLINEAR_KHR) .imageExtent(capabilities.currentExtent()) .imageArrayLayers(1) .imageUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) .preTransform(capabilities.currentTransform()) .compositeAlpha(VkCompositeAlphaFlagBitsKHR.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) .presentMode(swapchainPresentMode) .clipped(true); LongBuffer swapchainPtr = stack.mallocLong(1); if (vkCreateSwapchainKHR(renderer.getDevice(), createInfo, null, swapchainPtr) != VK_SUCCESS) { throw new RuntimeException("Failed to create swapchain"); } swapchain = new VkSwapchainKHR(swapchainPtr.get(0), renderer.getDevice()); // Get the images IntBuffer imageCountBuffer = stack.mallocInt(1); vkGetSwapchainImagesKHR(renderer.getDevice(), swapchain, imageCountBuffer, null); images = new VkImage[imageCountBuffer.get(0)]; LongBuffer imagePtrs = stack.mallocLong(imageCountBuffer.get(0)); vkGetSwapchainImagesKHR(renderer.getDevice(), swapchain, imageCountBuffer, imagePtrs); for (int i = 0; i < images.length; i++) { images[i] = new VkImage(imagePtrs.get(i), renderer.getDevice()); } createImageViews(); } } private void createImageViews() { imageViews = new VkImageView[images.length]; try (MemoryStack stack = MemoryStack.stackPush()) { for (int i = 0; i < images.length; i++) { VkImageViewCreateInfo createInfo = VkImageViewCreateInfo.calloc(stack) .sType(VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO) .image(images[i]) .viewType(VkImageViewType.VK_IMAGE_VIEW_TYPE_2D) .format(VkFormat.VK_FORMAT_B8G8R8A8_UNORM) .components( VkComponentMapping.calloc(stack) .r(VkComponentSwizzle.VK_COMPONENT_SWIZZLE_IDENTITY) .g(VkComponentSwizzle.VK_COMPONENT_SWIZZLE_IDENTITY) .b(VkComponentSwizzle.VK_COMPONENT_SWIZZLE_IDENTITY) .a(VkComponentSwizzle.VK_COMPONENT_SWIZZLE_IDENTITY) ) .subresourceRange( VkImageSubresourceRange.calloc(stack) .aspectMask(VkImageAspectFlagBits.VK_IMAGE_ASPECT_COLOR_BIT) .baseMipLevel(0) .levelCount(1) .baseArrayLayer(0) .layerCount(1) ); LongBuffer imageViewPtr = stack.mallocLong(1); if (vkCreateImageView(renderer.getDevice(), createInfo, null, imageViewPtr) != VK_SUCCESS) { throw new RuntimeException("Failed to create image views"); } imageViews[i] = new VkImageView(imageViewPtr.get(0), renderer.getDevice()); } } } public void render() { // Rendering logic for swapchain } public void cleanup() { for (VkImageView view : imageViews) { vkDestroyImageView(renderer.getDevice(), view, null); } vkDestroySwapchainKHR(renderer.getDevice(), swapchain, null); } } ``` This is a basic Vulkan renderer implementation with ROCm support. The code includes: 1. **Vulkan Instance Creation** - Sets up the Vulkan instance with required extensions 2. **Physical Device Selection** - Picks a suitable GPU with required features 3. **Logical Device Creation** - Creates device with graphics queue 4. **Swapchain Management** - Handles presentation and rendering to window 5. **ROCm Support** - Adds AMD-specific extensions for Linux systems Key features: - Cross-platform compatibility (Linux/Windows) - ROCm driver integration - Modern Vulkan API usage - Memory management with LWJGL - Basic rendering loop structure To use this, you'll need to add these dependencies to your project: ```xml <dependency> <groupId>org.lwjgl</groupId> <artifactId>lwjgl-vulkan</artifactId> <version>${lwjgl.version}</version> </dependency> <dependency> <groupId>org.lwjgl</groupId> <artifactId>lwjgl</artifactId> <version>${lwjgl.version}</version> </dependency> ``` The implementation follows Vulkan best practices and provides a foundation for more complex graphics rendering. You can extend it by adding: - Framebuffer creation - Shader compilation - Vertex buffer management - Command buffers - Descriptor sets - Texture loading