From e0ad8862154db616a0f1997beaff3283755f3dc0 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:04:05 +0000 Subject: [PATCH 1/8] Add Native Wayland Support --- .../net/vulkanmod/config/VideoResolution.java | 51 +++++++++++++++++++ .../net/vulkanmod/mixin/InputConstantsM.java | 22 ++++++++ .../vulkanmod/mixin/debug/GlDebugInfoM.java | 2 +- .../mixin/render/MinecraftMixin.java | 19 +++++++ .../java/net/vulkanmod/vulkan/DeviceInfo.java | 12 ++++- .../vulkan/framebuffer/SwapChain.java | 23 ++++++++- src/main/resources/vulkanmod.mixins.json | 48 +++++++---------- 7 files changed, 144 insertions(+), 33 deletions(-) create mode 100644 src/main/java/net/vulkanmod/mixin/InputConstantsM.java diff --git a/src/main/java/net/vulkanmod/config/VideoResolution.java b/src/main/java/net/vulkanmod/config/VideoResolution.java index 032ebcb17..f6d822b71 100644 --- a/src/main/java/net/vulkanmod/config/VideoResolution.java +++ b/src/main/java/net/vulkanmod/config/VideoResolution.java @@ -2,6 +2,7 @@ import com.mojang.blaze3d.platform.VideoMode; import com.mojang.blaze3d.systems.RenderSystem; +import org.apache.commons.lang3.SystemUtils; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWVidMode; @@ -9,8 +10,12 @@ import java.util.List; import java.util.Optional; +import static net.vulkanmod.Initializer.LOGGER; +import static org.lwjgl.glfw.GLFW.*; + public class VideoResolution { private static VideoResolution[] videoResolutions; + private static final int activePlat = getSupportedPlat(); int width; int height; @@ -52,10 +57,56 @@ public int[] refreshRates() { public static void init() { RenderSystem.assertOnRenderThread(); + GLFW.glfwInitHint(GLFW_PLATFORM, activePlat); + LOGGER.info("Selecting Platform: "+getStringFromPlat(activePlat)); + LOGGER.info("GLFW: "+GLFW.glfwGetVersionString()); GLFW.glfwInit(); videoResolutions = populateVideoResolutions(GLFW.glfwGetPrimaryMonitor()); } + //Actually detect the currently active Display Server (if both Wayland and X11 are present on the system and/or GLFW is compiled to support both) + private static int determineDisplayServer() { + + //Return Null platform if not on Linux (i.e. no X11 or Wayland) + String xdgSessionType = System.getenv("XDG_SESSION_TYPE"); + if(xdgSessionType==null) return GLFW_ANY_PLATFORM; //Likely Android + return switch (xdgSessionType) { + case "wayland" -> GLFW_PLATFORM_WAYLAND; //Wayland + case "x11" -> GLFW_PLATFORM_X11; //X11 + default -> GLFW_ANY_PLATFORM; //Either unknown Platform or Display Server + }; + } + + private static int getSupportedPlat() { + //Switch statement would be ideal, but couldn't find a good way of implementing it, so fell back to basic if statements/branches + if(SystemUtils.IS_OS_WINDOWS) return GLFW_PLATFORM_WIN32; + if(SystemUtils.IS_OS_MAC_OSX) return GLFW_PLATFORM_COCOA; + if(SystemUtils.IS_OS_LINUX) return determineDisplayServer(); //Linux Or Android + + return GLFW_ANY_PLATFORM; //Unknown platform + } + + private static String getStringFromPlat(int plat) { + return switch (plat) + { + case GLFW_PLATFORM_WIN32 -> "WIN32"; + case GLFW_PLATFORM_WAYLAND -> "WAYLAND"; + case GLFW_PLATFORM_X11 -> "X11"; + case GLFW_PLATFORM_COCOA -> "MACOS"; + case GLFW_ANY_PLATFORM -> "ANDROID"; + default -> throw new IllegalStateException("Unexpected value: " + plat); + }; + } + + public static int getActivePlat() { return activePlat; } + + //Allows platform specific checks to be handled + public static boolean isWayLand() { return activePlat == GLFW_PLATFORM_WAYLAND; } + public static boolean isX11() { return activePlat == GLFW_PLATFORM_X11; } + public static boolean isWindows() { return activePlat == GLFW_PLATFORM_WIN32; } + public static boolean isMacOS() { return activePlat == GLFW_PLATFORM_COCOA; } + public static boolean isAndroid() { return activePlat == GLFW_ANY_PLATFORM; } + public static VideoResolution[] getVideoResolutions() { return videoResolutions; } diff --git a/src/main/java/net/vulkanmod/mixin/InputConstantsM.java b/src/main/java/net/vulkanmod/mixin/InputConstantsM.java new file mode 100644 index 000000000..f0c27aafd --- /dev/null +++ b/src/main/java/net/vulkanmod/mixin/InputConstantsM.java @@ -0,0 +1,22 @@ +package net.vulkanmod.mixin; + +import com.mojang.blaze3d.platform.InputConstants; +import net.vulkanmod.config.VideoResolution; +import org.lwjgl.glfw.*; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(InputConstants.class) +public class InputConstantsM { + /** + * @author + * @reason Setting the cursor position is not supported on Wayland + */ + @Overwrite + public static void grabOrReleaseMouse(long l, int i, double d, double e) { + if (!VideoResolution.isWayLand()) GLFW.glfwSetCursorPos(l, d, e); + GLFW.glfwSetInputMode(l, 208897, i); + } +} \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/mixin/debug/GlDebugInfoM.java b/src/main/java/net/vulkanmod/mixin/debug/GlDebugInfoM.java index c41e518ea..254c82b43 100644 --- a/src/main/java/net/vulkanmod/mixin/debug/GlDebugInfoM.java +++ b/src/main/java/net/vulkanmod/mixin/debug/GlDebugInfoM.java @@ -14,7 +14,7 @@ public class GlDebugInfoM { */ @Overwrite public static String getVendor() { - return Vulkan.getDeviceInfo() != null ? Vulkan.getDeviceInfo().vendorId : "n/a"; + return Vulkan.getDeviceInfo() != null ? Vulkan.getDeviceInfo().vendorIdString : "n/a"; } /** diff --git a/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java b/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java index 9fba301e4..9fec309cd 100644 --- a/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java @@ -1,8 +1,10 @@ package net.vulkanmod.mixin.render; import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.IconSet; import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.TimerQuery; +import net.minecraft.SharedConstants; import net.minecraft.Util; import net.minecraft.client.GraphicsStatus; import net.minecraft.client.Minecraft; @@ -18,8 +20,11 @@ import net.minecraft.client.resources.PaintingTextureManager; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.sounds.SoundManager; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.VanillaPackResources; import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.vulkanmod.Initializer; +import net.vulkanmod.config.VideoResolution; import net.vulkanmod.render.profiling.Profiler2; import net.vulkanmod.render.texture.SpriteUtil; import net.vulkanmod.vulkan.Renderer; @@ -36,6 +41,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.io.IOException; import java.util.Optional; @Mixin(Minecraft.class) @@ -67,6 +73,8 @@ private void forceGraphicsMode(GameConfig gameConfig, CallbackInfo ci) { } } + @Shadow @Final private VanillaPackResources vanillaPackResources; + @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V")) private void beginRender(int i, boolean bl) { Renderer.getInstance().beginFrame(); @@ -76,6 +84,17 @@ private void beginRender(int i, boolean bl) { private void submitRender(boolean tick, CallbackInfo ci) { Renderer.getInstance().endFrame(); } + /** + * @author + * @reason Only KWin supports setting the Icon on Wayland AFAIK + */ + @Redirect(method="", at=@At(value="INVOKE", target="Lcom/mojang/blaze3d/platform/Window;setIcon(Lnet/minecraft/server/packs/PackResources;Lcom/mojang/blaze3d/platform/IconSet;)V")) + private void bypassWaylandIcon(Window instance, PackResources packResources, IconSet iconSet) throws IOException { + if(!VideoResolution.isWayLand()) + { + this.window.setIcon(this.vanillaPackResources, SharedConstants.getCurrentVersion().isStable() ? IconSet.RELEASE : IconSet.SNAPSHOT); + } + } @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;bindWrite(Z)V")) private void redirectMainTarget1(RenderTarget instance, boolean bl) { diff --git a/src/main/java/net/vulkanmod/vulkan/DeviceInfo.java b/src/main/java/net/vulkanmod/vulkan/DeviceInfo.java index 81d0a4490..58d7f79dd 100644 --- a/src/main/java/net/vulkanmod/vulkan/DeviceInfo.java +++ b/src/main/java/net/vulkanmod/vulkan/DeviceInfo.java @@ -28,7 +28,8 @@ public class DeviceInfo { public static final List graphicsCards; private final VkPhysicalDevice device; - public final String vendorId; + private final int vendorId; + public final String vendorIdString; public final String deviceName; public final String driverVersion; public final String vkVersion; @@ -57,7 +58,8 @@ public DeviceInfo(VkPhysicalDevice device, VkPhysicalDeviceProperties properties } this.device = device; - this.vendorId = decodeVendor(properties.vendorID()); + this.vendorId = properties.vendorID(); + this.vendorIdString = decodeVendor(properties.vendorID()); this.deviceName = properties.deviceNameString(); this.driverVersion = decodeDvrVersion(Device.deviceProperties.driverVersion(), Device.deviceProperties.vendorID()); this.vkVersion = decDefVersion(getVkVer()); @@ -185,4 +187,10 @@ public static String debugString(PointerBuffer ppPhysicalDevices, Set re public boolean isDrawIndirectSupported() { return drawIndirectSupported; } + + //Added these to allow detecting GPU vendor, to allow handling vendor specific circumstances: + // (e.g. such as in case we encounter a vendor specific driver bug) + public boolean isAMD() { return vendorId == 0x1022; } + public boolean isNvidia() { return vendorId == 0x10DE; } + public boolean isIntel() { return vendorId == 0x8086; } } diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java index 445ced726..73bb563d9 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.List; +import static net.vulkanmod.vulkan.Device.device; import static net.vulkanmod.vulkan.Vulkan.*; import static net.vulkanmod.vulkan.util.VUtil.UINT32_MAX; import static org.lwjgl.glfw.GLFW.glfwGetFramebufferSize; @@ -33,6 +34,11 @@ public static int getDefaultDepthFormat() { return DEFAULT_DEPTH_FORMAT; } + //Necessary until tearing-control-unstable-v1 is fully implemented on all GPU Drivers for Wayland + //(As Immediate Mode (and by extension Screen tearing) doesn't exist on most Wayland installations currently) + //Try to use Mailbox if possible (in case FreeSync/G-Sync needs it) + private static final int defUncappedMode = checkPresentMode(VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR); + private RenderPass renderPass; private long[] framebuffers; @@ -354,7 +360,7 @@ private VkSurfaceFormatKHR getFormat(VkSurfaceFormatKHR.Buffer availableFormats) } private int getPresentMode(IntBuffer availablePresentModes) { - int requestedMode = vsync ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR; + int requestedMode = vsync ? VK_PRESENT_MODE_FIFO_KHR : defUncappedMode; //fifo mode is the only mode that has to be supported if(requestedMode == VK_PRESENT_MODE_FIFO_KHR) @@ -394,6 +400,21 @@ private static VkExtent2D getExtent(VkSurfaceCapabilitiesKHR capabilities) { return actualExtent; } + private static int checkPresentMode(int... requestedModes) { + try(MemoryStack stack = MemoryStack.stackPush()) + { + var a = Device.querySurfaceProperties(device.getPhysicalDevice(), stack).presentModes; + for(int dMode : requestedModes) { + for (int i = 0; i < a.capacity(); i++) { + if (a.get(i) == dMode) { + return dMode; + } + } + } + return VK_PRESENT_MODE_FIFO_KHR; //If None of the request modes exist/are supported by Driver + } + } + public boolean isVsync() { return vsync; } diff --git a/src/main/resources/vulkanmod.mixins.json b/src/main/resources/vulkanmod.mixins.json index f5ad59f25..0cbe9fbab 100644 --- a/src/main/resources/vulkanmod.mixins.json +++ b/src/main/resources/vulkanmod.mixins.json @@ -7,57 +7,52 @@ "mixins": [ ], "client": [ + "InputConstantsM", + "WindowMixin", "chunk.DirectionMixin", "chunk.FrustumMixin", "chunk.LevelRendererMixin", "chunk.VisibilitySetMixin", - - "compatibility.gl.GL11M", "compatibility.EffectInstanceM", "compatibility.ProgramM", "compatibility.UniformM", - + "compatibility.gl.GL11M", "debug.ChunkBorderRendererM", + "debug.DebugScreenOverlayM", "debug.GlDebugInfoM", "debug.KeyboardHandlerM", - "debug.DebugScreenOverlayM", - "gui.ChatComponentM", "gui.DebugHudM", "gui.GuiM", - "matrix.Matrix4fM", - "profiling.GuiMixin", "profiling.KeyboardHandlerM", - - "render.entity.EntityRendererM", - "render.model.ModelPartCubeM", - "render.model.ModelPartM", - "render.vertex.FaceBakeryM", - "render.vertex.BufferBuilderM", - "render.vertex.VertexBufferM", - "render.vertex.VertexConsumerM", - "render.vertex.LiquidBlockRendererM", - "render.vertex.VertexFormatMixin", "render.BufferUploaderM", - "render.RenderTargetMixin", "render.GameRendererMixin", "render.GlProgramManagerMixin", "render.GlStateManagerM", - "render.vertex.IndexTypeMixin", + "render.LevelRendererMixin", + "render.MainTargetMixin", "render.MinecraftMixin", "render.RenderSystemMixin", + "render.RenderTargetMixin", "render.ShaderInstanceM", - "render.MainTargetMixin", - "render.LevelRendererMixin", - + "render.entity.EntityRendererM", + "render.model.ModelPartCubeM", + "render.model.ModelPartM", + "render.vertex.BufferBuilderM", + "render.vertex.FaceBakeryM", + "render.vertex.IndexTypeMixin", + "render.vertex.LiquidBlockRendererM", + "render.vertex.VertexBufferM", + "render.vertex.VertexConsumerM", + "render.vertex.VertexFormatMixin", "screen.OptionsScreenM", - "texture.MAbstractTexture", "texture.MDynamicTexture", "texture.MFontTexture", "texture.MLightTexture", + "texture.MNativeImage", "texture.MOverlayTexture", "texture.MPlayerSkinTexture", "texture.MSimpleTexture", @@ -65,16 +60,11 @@ "texture.MSpriteContents", "texture.MTextureManager", "texture.MTextureUtil", - "texture.MNativeImage", - "util.ScreenshotRecorderM", - "vertex.SpriteCoordinateExpanderM", "vertex.VertexMultiConsumersM$DoubleM", "vertex.VertexMultiConsumersM$MultipleM", - "vertex.VertexMultiConsumersM$SheetDecalM", - - "WindowMixin" + "vertex.VertexMultiConsumersM$SheetDecalM" ], "injectors": { "defaultRequire": 1 From db81e822017b896c567457426840d03b1a00dc98 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:59:01 +0000 Subject: [PATCH 2/8] Use alternate Swapchain System Needed to fix Wayland stability on Mesa/RADV Driver --- .../java/net/vulkanmod/config/Config.java | 1 + .../java/net/vulkanmod/config/Options.java | 41 +++++++++++++-- .../render/chunk/AreaUploadManager.java | 4 +- .../java/net/vulkanmod/vulkan/Renderer.java | 52 +++++++++++-------- .../java/net/vulkanmod/vulkan/Vulkan.java | 4 +- .../vulkan/framebuffer/SwapChain.java | 26 ++++++---- .../vulkan/memory/IndirectBuffer.java | 2 +- .../vulkanmod/vulkan/memory/MemoryTypes.java | 6 +-- .../vulkan/memory/UniformBuffers.java | 10 ++-- .../vulkan/passes/DefaultMainPass.java | 4 +- .../vulkan/shader/GraphicsPipeline.java | 2 +- .../vulkanmod/vulkan/texture/VulkanImage.java | 4 +- 12 files changed, 99 insertions(+), 57 deletions(-) diff --git a/src/main/java/net/vulkanmod/config/Config.java b/src/main/java/net/vulkanmod/config/Config.java index b4a3e67e1..5fb6d8fcc 100644 --- a/src/main/java/net/vulkanmod/config/Config.java +++ b/src/main/java/net/vulkanmod/config/Config.java @@ -13,6 +13,7 @@ public class Config { public int frameQueueSize = 2; + public int minImageCount = 3; public VideoResolution resolution = VideoResolution.getFirstAvailable(); public boolean windowedFullscreen = false; public boolean guiOptimizations = false; diff --git a/src/main/java/net/vulkanmod/config/Options.java b/src/main/java/net/vulkanmod/config/Options.java index ef57f2fb7..0504898e1 100644 --- a/src/main/java/net/vulkanmod/config/Options.java +++ b/src/main/java/net/vulkanmod/config/Options.java @@ -3,11 +3,12 @@ import com.mojang.blaze3d.platform.Window; import net.minecraft.client.*; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.contents.LiteralContents; -import net.minecraft.network.chat.contents.TranslatableContents; import net.vulkanmod.Initializer; -import net.vulkanmod.vulkan.Drawer; +import net.vulkanmod.vulkan.Device; import net.vulkanmod.vulkan.Renderer; +import org.lwjgl.system.MemoryStack; + +import static net.vulkanmod.vulkan.Device.device; public class Options { static net.minecraft.client.Options minecraftOptions = Minecraft.getInstance().options; @@ -15,6 +16,24 @@ public class Options { static Window window = Minecraft.getInstance().getWindow(); public static boolean fullscreenDirty = false; + private static final int minImages; + + private static final int maxImages; + + + static + { + try(MemoryStack stack = MemoryStack.stackPush()) + { + Device.SurfaceProperties surfaceProperties = Device.querySurfaceProperties(device.getPhysicalDevice(), stack); + minImages = surfaceProperties.capabilities.minImageCount(); + int maxImageCount = surfaceProperties.capabilities.maxImageCount(); + + boolean hasInfiniteSwapChain = maxImageCount == 0; //Applicable if Mesa/RADV Driver are present + maxImages = hasInfiniteSwapChain ? 64 : maxImageCount; + } + } + public static Option[] getVideoOpts() { return new Option[] { @@ -168,14 +187,26 @@ public static Option[] getGraphicsOpts() { public static Option[] getOtherOpts() { return new Option[] { - new RangeOption("Queue Frames", 2, + new RangeOption("Queue Frames", 1, 5, 1, value -> { config.frameQueueSize = value; Renderer.scheduleSwapChainUpdate(); }, () -> config.frameQueueSize) .setTooltip(Component.nullToEmpty(""" - Sets the number of queue frames""")), + Manages the tradeoff between FPS and input lag + Most GPUs only require 2 for max performance + and usually don't have any performance benefits with 3 or higher""")), + new RangeOption("SwapChain Images", minImages, + maxImages, 1, + value -> { + config.minImageCount = value; + Renderer.scheduleSwapChainUpdate(); + }, () -> config.minImageCount) + .setTooltip(Component.nullToEmpty(""" + Sets the number of Swapchain images + Optimised automatically for best performance + This can be reduced to minimise input lag but at the cost of decreased FPS""")), new SwitchOption("Gui Optimizations", value -> config.guiOptimizations = value, () -> config.guiOptimizations) diff --git a/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java b/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java index cfc5b6015..4940e621d 100644 --- a/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java +++ b/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java @@ -56,7 +56,7 @@ public void uploadAsync(AreaBuffer.Segment uploadSegment, long bufferId, long ds VkCommandBuffer commandBuffer = commandBuffers[currentFrame].getHandle(); - StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(this.currentFrame); + StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(); stagingBuffer.copyBuffer((int) bufferSize, src); if(!dstBuffers.add(bufferId)) { @@ -83,7 +83,7 @@ public void uploadAsync(AreaBuffer.Segment uploadSegment, long bufferId, long ds } public void updateFrame() { - this.currentFrame = (this.currentFrame + 1) % FRAME_NUM; + this.currentFrame ^= this.currentFrame; waitUploads(this.currentFrame); this.dstBuffers.clear(); diff --git a/src/main/java/net/vulkanmod/vulkan/Renderer.java b/src/main/java/net/vulkanmod/vulkan/Renderer.java index ef0f022e7..fa1b80809 100644 --- a/src/main/java/net/vulkanmod/vulkan/Renderer.java +++ b/src/main/java/net/vulkanmod/vulkan/Renderer.java @@ -41,7 +41,6 @@ public class Renderer { private static boolean swapCahinUpdate = false; public static boolean skipRendering = false; - public static void initRenderer() { INSTANCE = new Renderer(); } public static Renderer getInstance() { return INSTANCE; } @@ -50,11 +49,14 @@ public class Renderer { public static int getCurrentFrame() { return currentFrame; } + public static int getCurrentImage() { return imageIndex; } + private final Set usedPipelines = new ObjectOpenHashSet<>(); private final Drawer drawer; private int framesNum; + private int imagesNum; private List commandBuffers; private ArrayList imageAvailableSemaphores; private ArrayList renderFinishedSemaphores; @@ -64,6 +66,7 @@ public class Renderer { private RenderPass boundRenderPass; private static int currentFrame = 0; + private static int imageIndex; private VkCommandBuffer currentCmdBuffer; MainPass mainPass = DefaultMainPass.PASS; @@ -77,7 +80,8 @@ public Renderer() { TerrainShaderManager.init(); AreaUploadManager.createInstance(); - framesNum = getSwapChainImages().size(); + framesNum = getSwapChain().getFramesNum(); + imagesNum = getSwapChain().getImagesNum(); drawer = new Drawer(); drawer.createResources(framesNum); @@ -197,6 +201,27 @@ public void beginFrame() { try(MemoryStack stack = stackPush()) { + IntBuffer pImageIndex = stack.mallocInt(1); + + int vkResult = vkAcquireNextImageKHR(device, Vulkan.getSwapChain().getId(), VUtil.UINT64_MAX, + imageAvailableSemaphores.get(currentFrame), VK_NULL_HANDLE, pImageIndex); + + if(vkResult == VK_SUBOPTIMAL_KHR ) { + swapCahinUpdate = true; + } + if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || swapCahinUpdate) { + swapCahinUpdate = true; +// shouldRecreate = false; +// waitForSwapChain(); +// recreateSwapChain(); +// shouldRecreate = true; + return; + } else if(vkResult != VK_SUCCESS) { + throw new RuntimeException("Cannot get image: " + vkResult); + } + + imageIndex = pImageIndex.get(0); + VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.calloc(stack); beginInfo.sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO); beginInfo.flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); @@ -273,7 +298,7 @@ public void resetBuffers() { drawer.resetBuffers(currentFrame); AreaUploadManager.INSTANCE.updateFrame(); - Vulkan.getStagingBuffer(currentFrame).reset(); + Vulkan.getStagingBuffer().reset(); } public void addUsedPipeline(Pipeline pipeline) { @@ -296,23 +321,7 @@ private void submitFrame() { try(MemoryStack stack = stackPush()) { - IntBuffer pImageIndex = stack.mallocInt(1); - - int vkResult = vkAcquireNextImageKHR(device, Vulkan.getSwapChain().getId(), VUtil.UINT64_MAX, - imageAvailableSemaphores.get(currentFrame), VK_NULL_HANDLE, pImageIndex); - - if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || vkResult == VK_SUBOPTIMAL_KHR || swapCahinUpdate) { - swapCahinUpdate = true; -// shouldRecreate = false; -// waitForSwapChain(); -// recreateSwapChain(); -// shouldRecreate = true; - return; - } else if(vkResult != VK_SUCCESS) { - throw new RuntimeException("Cannot get image: " + vkResult); - } - - final int imageIndex = pImageIndex.get(0); + int vkResult; VkSubmitInfo submitInfo = VkSubmitInfo.calloc(stack); submitInfo.sType(VK_STRUCTURE_TYPE_SUBMIT_INFO); @@ -342,7 +351,7 @@ private void submitFrame() { presentInfo.swapchainCount(1); presentInfo.pSwapchains(stack.longs(Vulkan.getSwapChain().getId())); - presentInfo.pImageIndices(pImageIndex); + presentInfo.pImageIndices(stack.ints(imageIndex)); vkResult = vkQueuePresentKHR(Device.getPresentQueue().queue(), presentInfo); @@ -387,6 +396,7 @@ private void recreateSwapChain() { destroySyncObjects(); int newFramesNum = getSwapChain().getFramesNum(); + imagesNum = getSwapChain().getFramesNum(); if(framesNum != newFramesNum) { AreaUploadManager.INSTANCE.waitAllUploads(); diff --git a/src/main/java/net/vulkanmod/vulkan/Vulkan.java b/src/main/java/net/vulkanmod/vulkan/Vulkan.java index 27e67cc56..07db5d752 100644 --- a/src/main/java/net/vulkanmod/vulkan/Vulkan.java +++ b/src/main/java/net/vulkanmod/vulkan/Vulkan.java @@ -160,7 +160,7 @@ static void createStagingBuffers() { Arrays.stream(stagingBuffers).forEach(Buffer::freeBuffer); } - stagingBuffers = new StagingBuffer[getSwapChainImages().size()]; + stagingBuffers = new StagingBuffer[getSwapChain().getFramesNum()]; for(int i = 0; i < stagingBuffers.length; ++i) { stagingBuffers[i] = new StagingBuffer(30 * 1024 * 1024); @@ -469,7 +469,7 @@ public static long getCommandPool() return commandPool; } - public static StagingBuffer getStagingBuffer(int i) { return stagingBuffers[i]; } + public static StagingBuffer getStagingBuffer() { return stagingBuffers[Renderer.getCurrentFrame()]; } public static DeviceInfo getDeviceInfo() { return Device.deviceInfo; } } diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java index 73bb563d9..1a82d95f9 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java @@ -76,11 +76,10 @@ public int recreateSwapChain() { createSwapChain(); - return this.swapChainImages.size(); + return this.getFramesNum(); } public void createSwapChain() { - int requestedFrames = Initializer.CONFIG.frameQueueSize; try(MemoryStack stack = stackPush()) { VkDevice device = Vulkan.getDevice(); @@ -101,15 +100,15 @@ public void createSwapChain() { this.height = 0; return; } + //minImageCount depends on driver: Mesa/RADV needs a min of 4, but most other drivers are at least 2 or 3 + if(Initializer.CONFIG.minImageCount < surfaceProperties.capabilities.minImageCount()) + Initializer.CONFIG.minImageCount = surfaceProperties.capabilities.minImageCount(); + + int requestedFrames = Initializer.CONFIG.minImageCount; - //Workaround for Mesa IntBuffer imageCount = stack.ints(requestedFrames); // IntBuffer imageCount = stack.ints(Math.max(surfaceProperties.capabilities.minImageCount(), preferredImageCount)); - if(surfaceProperties.capabilities.maxImageCount() > 0 && imageCount.get(0) > surfaceProperties.capabilities.maxImageCount()) { - imageCount.put(0, surfaceProperties.capabilities.maxImageCount()); - } - VkSwapchainCreateInfoKHR createInfo = VkSwapchainCreateInfoKHR.callocStack(stack); createInfo.sType(VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); @@ -119,7 +118,7 @@ public void createSwapChain() { this.format = surfaceFormat.format(); this.extent2D = VkExtent2D.create().set(extent); - createInfo.minImageCount(imageCount.get(0)); + createInfo.minImageCount(requestedFrames); createInfo.imageFormat(this.format); createInfo.imageColorSpace(surfaceFormat.colorSpace()); createInfo.imageExtent(extent); @@ -163,6 +162,10 @@ public void createSwapChain() { swapChainImages = new ArrayList<>(imageCount.get(0)); + // minImageCount and Actual Image Count can differ with some Drivers, + // According to the spec, minImageCount is only the guaranteed min, not the actual image count + Initializer.LOGGER.info("Requested Images: "+requestedFrames + " -> Actual Image Count: "+imageCount.get(0)); + this.width = extent2D.width(); this.height = extent2D.height(); @@ -232,7 +235,7 @@ public void beginRenderPass(VkCommandBuffer commandBuffer, MemoryStack stack) { this.renderPass.beginDynamicRendering(commandBuffer, stack); } else { - this.renderPass.beginRenderPass(commandBuffer, this.framebuffers[Renderer.getCurrentFrame()], stack); + this.renderPass.beginRenderPass(commandBuffer, this.framebuffers[Renderer.getCurrentImage()], stack); } Renderer.getInstance().setBoundRenderPass(renderPass); @@ -335,7 +338,7 @@ public VkExtent2D getExtent() { } public VulkanImage getColorAttachment() { - return this.swapChainImages.get(Renderer.getCurrentFrame()); + return this.swapChainImages.get(Renderer.getCurrentImage()); } public long getImageView(int i) { return this.swapChainImages.get(i).getImageView(); } @@ -427,5 +430,6 @@ public RenderPass getRenderPass() { return renderPass; } - public int getFramesNum() { return this.swapChainImages.size(); } + public int getFramesNum() { return Initializer.CONFIG.frameQueueSize; } + public int getImagesNum() { return this.swapChainImages.size(); } } diff --git a/src/main/java/net/vulkanmod/vulkan/memory/IndirectBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/IndirectBuffer.java index 91bd0d8a3..b1780d6a4 100644 --- a/src/main/java/net/vulkanmod/vulkan/memory/IndirectBuffer.java +++ b/src/main/java/net/vulkanmod/vulkan/memory/IndirectBuffer.java @@ -30,7 +30,7 @@ public void recordCopyCmd(ByteBuffer byteBuffer) { if(commandBuffer == null) commandBuffer = Device.getTransferQueue().beginCommands(); - StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(Renderer.getCurrentFrame()); + StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(); stagingBuffer.copyBuffer(size, byteBuffer); TransferQueue.uploadBufferCmd(commandBuffer.getHandle(), stagingBuffer.id, stagingBuffer.offset, this.getId(), this.getUsedBytes(), size); diff --git a/src/main/java/net/vulkanmod/vulkan/memory/MemoryTypes.java b/src/main/java/net/vulkanmod/vulkan/memory/MemoryTypes.java index 0b8724693..384a4c5c8 100644 --- a/src/main/java/net/vulkanmod/vulkan/memory/MemoryTypes.java +++ b/src/main/java/net/vulkanmod/vulkan/memory/MemoryTypes.java @@ -1,8 +1,6 @@ package net.vulkanmod.vulkan.memory; import net.vulkanmod.vulkan.Device; -import net.vulkanmod.vulkan.Renderer; -import net.vulkanmod.vulkan.queue.TransferQueue; import net.vulkanmod.vulkan.Vulkan; import net.vulkanmod.vulkan.util.VUtil; import org.lwjgl.vulkan.VkMemoryType; @@ -65,7 +63,7 @@ void createBuffer(Buffer buffer, int size) { @Override void copyToBuffer(Buffer buffer, long bufferSize, ByteBuffer byteBuffer) { - StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(Renderer.getCurrentFrame()); + StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(); stagingBuffer.copyBuffer((int) bufferSize, byteBuffer); Device.getTransferQueue().copyBufferCmd(stagingBuffer.id, stagingBuffer.offset, buffer.getId(), buffer.getUsedBytes(), bufferSize); @@ -87,7 +85,7 @@ public long copyBuffer(Buffer src, Buffer dst) { @Override void uploadBuffer(Buffer buffer, ByteBuffer byteBuffer) { int bufferSize = byteBuffer.remaining(); - StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(Renderer.getCurrentFrame()); + StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(); stagingBuffer.copyBuffer(bufferSize, byteBuffer); Device.getTransferQueue().copyBufferCmd(stagingBuffer.id, stagingBuffer.offset, buffer.getId(), 0, bufferSize); diff --git a/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java b/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java index 3ed0be210..fb9e65677 100644 --- a/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java +++ b/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java @@ -9,7 +9,7 @@ import java.util.ArrayList; import java.util.List; -import static net.vulkanmod.vulkan.Vulkan.getSwapChainImages; +import static net.vulkanmod.vulkan.Vulkan.getSwapChain; import static net.vulkanmod.vulkan.util.VUtil.align; import static org.lwjgl.vulkan.VK10.VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; @@ -21,7 +21,7 @@ public class UniformBuffers { private List uniformBuffers; private final static int minOffset = (int) Device.deviceProperties.limits().minUniformBufferOffsetAlignment(); - private final int imagesSize = getSwapChainImages().size(); + private final int framesSize = getSwapChain().getFramesNum(); CommandPool.CommandBuffer commandBuffer; @@ -36,9 +36,9 @@ public UniformBuffers(int size, MemoryType memoryType) { private void createUniformBuffers(int size, MemoryType memoryType) { this.bufferSize = size; - uniformBuffers = new ArrayList<>(imagesSize); + uniformBuffers = new ArrayList<>(framesSize); - for(int i = 0; i < imagesSize; ++i) { + for(int i = 0; i < framesSize; ++i) { uniformBuffers.add(new UniformBuffer(this.bufferSize, memoryType)); } } @@ -127,7 +127,7 @@ public void uploadUBO(ByteBuffer buffer, int offset) { int size = buffer.remaining(); - StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(Renderer.getCurrentFrame()); + StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(); stagingBuffer.copyBuffer(size, buffer); TransferQueue.uploadBufferCmd(commandBuffer.getHandle(), stagingBuffer.id, stagingBuffer.offset, this.id, offset, size); diff --git a/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java b/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java index d7ecee56e..8e4956ea7 100644 --- a/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java +++ b/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java @@ -19,7 +19,7 @@ public class DefaultMainPass implements MainPass { @Override public void begin(VkCommandBuffer commandBuffer, MemoryStack stack) { SwapChain swapChain = Vulkan.getSwapChain(); - swapChain.colorAttachmentLayout(stack, commandBuffer, Renderer.getCurrentFrame()); + swapChain.colorAttachmentLayout(stack, commandBuffer, Renderer.getCurrentImage()); Framebuffer framebuffer = swapChain; swapChain.beginRenderPass(commandBuffer, stack); @@ -67,7 +67,7 @@ public void end(VkCommandBuffer commandBuffer) { Framebuffer.endRenderPass(commandBuffer); try(MemoryStack stack = MemoryStack.stackPush()) { - Vulkan.getSwapChain().presentLayout(stack, commandBuffer, Renderer.getCurrentFrame()); + Vulkan.getSwapChain().presentLayout(stack, commandBuffer, Renderer.getCurrentImage()); } int result = vkEndCommandBuffer(commandBuffer); diff --git a/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java index e273533d1..ba83c7650 100644 --- a/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java +++ b/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java @@ -46,7 +46,7 @@ public class GraphicsPipeline extends Pipeline { graphicsPipelines.computeIfAbsent(new PipelineState(DEFAULT_BLEND_STATE, DEFAULT_DEPTH_STATE, DEFAULT_LOGICOP_STATE, DEFAULT_COLORMASK, builder.renderPass), this::createGraphicsPipeline); - createDescriptorSets(Vulkan.getSwapChainImages().size()); + createDescriptorSets(Vulkan.getSwapChain().getFramesNum()); PIPELINES.add(this); } diff --git a/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java b/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java index c732b834b..53e4c29f3 100644 --- a/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java +++ b/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java @@ -7,7 +7,6 @@ import net.vulkanmod.vulkan.memory.MemoryManager; import net.vulkanmod.vulkan.memory.StagingBuffer; import net.vulkanmod.vulkan.queue.CommandPool; -import net.vulkanmod.vulkan.queue.GraphicsQueue; import net.vulkanmod.vulkan.util.VUtil; import org.lwjgl.PointerBuffer; import org.lwjgl.system.MemoryStack; @@ -20,7 +19,6 @@ import static net.vulkanmod.vulkan.Vulkan.*; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; -import static org.lwjgl.vulkan.VK12.VK_SAMPLER_REDUCTION_MODE_MIN; public class VulkanImage { public static int DefaultFormat = VK_FORMAT_R8G8B8A8_UNORM; @@ -153,7 +151,7 @@ public void uploadSubTextureAsync(int mipLevel, int width, int height, int xOffs CommandPool.CommandBuffer commandBuffer = Device.getGraphicsQueue().getCommandBuffer(); transferDstLayout(commandBuffer); - StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(Renderer.getCurrentFrame()); + StagingBuffer stagingBuffer = Vulkan.getStagingBuffer(); stagingBuffer.align(this.formatSize); stagingBuffer.copyBuffer((int)imageSize, buffer); From e9ca8233a261f5f14ccc10624a71b2ea8e391258 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:08:56 +0000 Subject: [PATCH 3/8] .Misc Nvidia + Performance Optimisations --- .../java/net/vulkanmod/vulkan/Device.java | 17 ++-- .../java/net/vulkanmod/vulkan/Renderer.java | 83 ++++++------------- .../vulkan/framebuffer/Framebuffer.java | 8 +- .../vulkan/framebuffer/RenderPass.java | 29 ++++--- .../vulkan/passes/DefaultMainPass.java | 17 ++-- .../vulkanmod/vulkan/texture/VulkanImage.java | 8 +- 6 files changed, 63 insertions(+), 99 deletions(-) diff --git a/src/main/java/net/vulkanmod/vulkan/Device.java b/src/main/java/net/vulkanmod/vulkan/Device.java index 52ae3c64e..72a2f25a3 100644 --- a/src/main/java/net/vulkanmod/vulkan/Device.java +++ b/src/main/java/net/vulkanmod/vulkan/Device.java @@ -268,29 +268,28 @@ private static boolean checkDeviceExtensionSupport(VkPhysicalDevice device) { .containsAll(Vulkan.REQUIRED_EXTENSION); } } - + // Use the optimal most performant depth format for the specific GPU + // Nvidia performs best with 24 bit depth, while AMD is most performant with 32-bit float public static int findDepthFormat() { return findSupportedFormat( - stackGet().ints(VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT), VK_IMAGE_TILING_OPTIMAL, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT); } - private static int findSupportedFormat(IntBuffer formatCandidates, int tiling, int features) { + private static int findSupportedFormat(int tiling, int features, int... formatCandidates) { try(MemoryStack stack = stackPush()) { VkFormatProperties props = VkFormatProperties.calloc(stack); - for(int i = 0; i < formatCandidates.capacity(); ++i) { - - int format = formatCandidates.get(i); + for (int format : formatCandidates) { vkGetPhysicalDeviceFormatProperties(physicalDevice, format, props); - if(tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures() & features) == features) { + if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures() & features) == features) { return format; - } else if(tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures() & features) == features) { + } else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures() & features) == features) { return format; } diff --git a/src/main/java/net/vulkanmod/vulkan/Renderer.java b/src/main/java/net/vulkanmod/vulkan/Renderer.java index fa1b80809..8353a1af9 100644 --- a/src/main/java/net/vulkanmod/vulkan/Renderer.java +++ b/src/main/java/net/vulkanmod/vulkan/Renderer.java @@ -209,7 +209,7 @@ public void beginFrame() { if(vkResult == VK_SUBOPTIMAL_KHR ) { swapCahinUpdate = true; } - if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || swapCahinUpdate) { + else if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || swapCahinUpdate) { swapCahinUpdate = true; // shouldRecreate = false; // waitForSwapChain(); @@ -487,74 +487,39 @@ public static void clearAttachments(int v) { if(framebuffer == null) return; - clearAttachments(v, framebuffer.getWidth(), framebuffer.getHeight()); + clearDepthAttachment(v, framebuffer.getWidth(), framebuffer.getHeight()); } - public static void clearAttachments(int v, int width, int height) { - if(skipRendering) + public static void clearDepthAttachment(int v, int width, int height) { + if(skipRendering || v == 0x4000 || v == 0x4100) return; - VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer; - try(MemoryStack stack = stackPush()) { //ClearValues have to be different for each attachment to clear, it seems it works like a buffer: color and depth attributes override themselves - VkClearValue colorValue = VkClearValue.calloc(stack); - colorValue.color().float32(VRenderSystem.clearColor); - - VkClearValue depthValue = VkClearValue.calloc(stack); - depthValue.depthStencil().depth(VRenderSystem.clearDepth); - - int attachmentsCount; - VkClearAttachment.Buffer pAttachments; - if (v == 0x100) { - attachmentsCount = 1; - - pAttachments = VkClearAttachment.calloc(attachmentsCount, stack); - VkClearAttachment clearDepth = pAttachments.get(0); - clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); - clearDepth.clearValue(depthValue); - } else if (v == 0x4000) { - attachmentsCount = 1; - - pAttachments = VkClearAttachment.calloc(attachmentsCount, stack); - - VkClearAttachment clearColor = pAttachments.get(0); - clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT); - clearColor.colorAttachment(0); - clearColor.clearValue(colorValue); - } else if (v == 0x4100) { - attachmentsCount = 2; - - pAttachments = VkClearAttachment.calloc(attachmentsCount, stack); - - VkClearAttachment clearColor = pAttachments.get(0); - clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT); - clearColor.clearValue(colorValue); - - VkClearAttachment clearDepth = pAttachments.get(1); - clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); - clearDepth.clearValue(depthValue); - } else { - throw new RuntimeException("unexpected value"); - } + + VkClearAttachment.Buffer clearDepth = VkClearAttachment.malloc(1, stack); + clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); + clearDepth.clearValue().depthStencil().set(VRenderSystem.clearDepth, 0); + //Rect to clear - VkRect2D renderArea = VkRect2D.calloc(stack); - renderArea.offset(VkOffset2D.calloc(stack).set(0, 0)); - renderArea.extent(VkExtent2D.calloc(stack).set(width, height)); + VkRect2D renderArea = VkRect2D.malloc(stack); + renderArea.offset().set(0, 0); + renderArea.extent().set(width, height); - VkClearRect.Buffer pRect = VkClearRect.calloc(1, stack); - pRect.get(0).rect(renderArea); - pRect.get(0).layerCount(1); + VkClearRect.Buffer pRect = VkClearRect.malloc(1, stack); + pRect.rect(renderArea); + pRect.baseArrayLayer(0); + pRect.layerCount(1); - vkCmdClearAttachments(commandBuffer, pAttachments, pRect); + vkCmdClearAttachments(INSTANCE.currentCmdBuffer, clearDepth, pRect); } } public static void setViewport(int x, int y, int width, int height) { try(MemoryStack stack = stackPush()) { - VkViewport.Buffer viewport = VkViewport.calloc(1, stack); + VkViewport.Buffer viewport = VkViewport.malloc(1, stack); viewport.x(x); viewport.y(height + y); viewport.width(width); @@ -563,8 +528,8 @@ public static void setViewport(int x, int y, int width, int height) { viewport.maxDepth(1.0f); VkRect2D.Buffer scissor = VkRect2D.malloc(1, stack); - scissor.offset(VkOffset2D.malloc(stack).set(0, 0)); - scissor.extent(VkExtent2D.malloc(stack).set(width, height)); + scissor.offset().set(0, 0); + scissor.extent().set(width, height); vkCmdSetViewport(INSTANCE.currentCmdBuffer, 0, viewport); vkCmdSetScissor(INSTANCE.currentCmdBuffer, 0, scissor); @@ -573,11 +538,11 @@ public static void setViewport(int x, int y, int width, int height) { public static void setScissor(int x, int y, int width, int height) { try(MemoryStack stack = stackPush()) { - int framebufferHeight = Renderer.getInstance().boundFramebuffer.getHeight(); + int framebufferHeight = INSTANCE.boundFramebuffer.getHeight(); VkRect2D.Buffer scissor = VkRect2D.malloc(1, stack); - scissor.offset(VkOffset2D.malloc(stack).set(x, framebufferHeight - (y + height))); - scissor.extent(VkExtent2D.malloc(stack).set(width, height)); + scissor.offset().set(x, framebufferHeight - (y + height)); + scissor.extent().set(width, height); vkCmdSetScissor(INSTANCE.currentCmdBuffer, 0, scissor); } @@ -588,7 +553,7 @@ public static void resetScissor() { return; try(MemoryStack stack = stackPush()) { - VkRect2D.Buffer scissor = Renderer.getInstance().boundFramebuffer.scissor(stack); + VkRect2D.Buffer scissor = INSTANCE.boundFramebuffer.scissor(stack); vkCmdSetScissor(INSTANCE.currentCmdBuffer, 0, scissor); } } diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java index ed35460e6..421a000a9 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java @@ -151,7 +151,7 @@ public void bindAsTexture(VkCommandBuffer commandBuffer, MemoryStack stack) { } public VkViewport.Buffer viewport(MemoryStack stack) { - VkViewport.Buffer viewport = VkViewport.callocStack(1, stack); + VkViewport.Buffer viewport = VkViewport.malloc(1, stack); viewport.x(0.0f); viewport.y(this.height); viewport.width(this.width); @@ -163,9 +163,9 @@ public VkViewport.Buffer viewport(MemoryStack stack) { } public VkRect2D.Buffer scissor(MemoryStack stack) { - VkRect2D.Buffer scissor = VkRect2D.callocStack(1, stack); - scissor.offset(VkOffset2D.callocStack(stack).set(0, 0)); - scissor.extent(VkExtent2D.malloc(stack).set(this.width, this.height)); + VkRect2D.Buffer scissor = VkRect2D.malloc(1, stack); + scissor.offset().set(0, 0); + scissor.extent().set(this.width, this.height); return scissor; } diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java index 648ac7112..b74045285 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java @@ -9,6 +9,7 @@ import java.nio.LongBuffer; +import static org.lwjgl.vulkan.KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; import static org.lwjgl.vulkan.VK10.*; public class RenderPass { @@ -66,7 +67,7 @@ private void createRenderPass() { colorAttachment.stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE); colorAttachment.initialLayout(colorAttachmentInfo.initialLayout); - colorAttachment.finalLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + colorAttachment.finalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); VkAttachmentReference colorAttachmentRef = attachmentRefs.get(0); colorAttachmentRef.attachment(0); @@ -111,7 +112,7 @@ private void createRenderPass() { id = pRenderPass.get(0); - finalColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + finalColorLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; finalDepthLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } @@ -128,18 +129,17 @@ public void beginRenderPass(VkCommandBuffer commandBuffer, long framebufferId, M // throw new RuntimeException("current layout does not match expected initial layout"); framebuffer.getDepthAttachment().transitionImageLayout(stack, commandBuffer, depthAttachmentInfo.initialLayout); - VkRenderPassBeginInfo renderPassInfo = VkRenderPassBeginInfo.callocStack(stack); + VkRenderPassBeginInfo renderPassInfo = VkRenderPassBeginInfo.calloc(stack); renderPassInfo.sType$Default(); renderPassInfo.renderPass(this.id); renderPassInfo.framebuffer(framebufferId); - VkRect2D renderArea = VkRect2D.calloc(stack); - renderArea.offset(VkOffset2D.calloc(stack).set(0, 0)); - renderArea.extent(VkExtent2D.calloc(stack).set(framebuffer.getWidth(), framebuffer.getHeight())); + VkRect2D renderArea = VkRect2D.malloc(stack); + renderArea.offset().set(0, 0); + renderArea.extent().set(framebuffer.getWidth(), framebuffer.getHeight()); renderPassInfo.renderArea(renderArea); - VkClearValue.Buffer clearValues; - clearValues = VkClearValue.calloc(2, stack); + VkClearValue.Buffer clearValues = VkClearValue.malloc(2, stack); clearValues.get(0).color().float32(VRenderSystem.clearColor); clearValues.get(1).depthStencil().set(1.0f, 0); @@ -163,12 +163,11 @@ public void endRenderPass(VkCommandBuffer commandBuffer) { } public void beginDynamicRendering(VkCommandBuffer commandBuffer, MemoryStack stack) { - VkRect2D renderArea = VkRect2D.calloc(stack); - renderArea.offset(VkOffset2D.calloc(stack).set(0, 0)); - renderArea.extent(VkExtent2D.calloc(stack).set(framebuffer.getWidth(), framebuffer.getHeight())); + VkRect2D renderArea = VkRect2D.malloc(stack); + renderArea.offset().set(0, 0); + renderArea.extent().set(framebuffer.getWidth(), framebuffer.getHeight()); - VkClearValue.Buffer clearValues; - clearValues = VkClearValue.calloc(2, stack); + VkClearValue.Buffer clearValues = VkClearValue.malloc(2, stack); clearValues.get(0).color().float32(stack.floats(0.0f, 0.0f, 0.0f, 1.0f)); clearValues.get(1).depthStencil().set(1.0f, 0); @@ -276,9 +275,9 @@ public Builder(Framebuffer framebuffer) { this.framebuffer = framebuffer; if(framebuffer.hasColorAttachment) - colorAttachmentInfo = new AttachmentInfo(AttachmentInfo.Type.COLOR, framebuffer.format); + colorAttachmentInfo = new AttachmentInfo(AttachmentInfo.Type.COLOR, framebuffer.format).setOps(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); if(framebuffer.hasDepthAttachment) - depthAttachmentInfo = new AttachmentInfo(AttachmentInfo.Type.DEPTH, framebuffer.depthFormat); + depthAttachmentInfo = new AttachmentInfo(AttachmentInfo.Type.DEPTH, framebuffer.depthFormat).setOps(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE); } public RenderPass build() { diff --git a/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java b/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java index 8e4956ea7..07e39b0b6 100644 --- a/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java +++ b/src/main/java/net/vulkanmod/vulkan/passes/DefaultMainPass.java @@ -19,23 +19,22 @@ public class DefaultMainPass implements MainPass { @Override public void begin(VkCommandBuffer commandBuffer, MemoryStack stack) { SwapChain swapChain = Vulkan.getSwapChain(); - swapChain.colorAttachmentLayout(stack, commandBuffer, Renderer.getCurrentImage()); +// swapChain.colorAttachmentLayout(stack, commandBuffer, Renderer.getCurrentImage()); - Framebuffer framebuffer = swapChain; swapChain.beginRenderPass(commandBuffer, stack); - Renderer.clearAttachments(0x4100, swapChain.getWidth(), swapChain.getHeight()); +// Renderer.clearAttachments(0x4100, swapChain.getWidth(), swapChain.getHeight()); // Framebuffer framebuffer = this.hdrFinalFramebuffer; // framebuffer.getColorAttachment().transitionImageLayout(stack, commandBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // // framebuffer.beginRenderPass(commandBuffer, renderPass, stack); // this.boundFramebuffer = framebuffer; - Renderer.getInstance().setBoundFramebuffer(framebuffer); + Renderer.getInstance().setBoundFramebuffer(swapChain); - VkViewport.Buffer pViewport = framebuffer.viewport(stack); + VkViewport.Buffer pViewport = swapChain.viewport(stack); vkCmdSetViewport(commandBuffer, 0, pViewport); - VkRect2D.Buffer pScissor = framebuffer.scissor(stack); + VkRect2D.Buffer pScissor = swapChain.scissor(stack); vkCmdSetScissor(commandBuffer, 0, pScissor); } @@ -66,9 +65,9 @@ public void end(VkCommandBuffer commandBuffer) { Framebuffer.endRenderPass(commandBuffer); - try(MemoryStack stack = MemoryStack.stackPush()) { - Vulkan.getSwapChain().presentLayout(stack, commandBuffer, Renderer.getCurrentImage()); - } +// try(MemoryStack stack = MemoryStack.stackPush()) { +// Vulkan.getSwapChain().presentLayout(stack, commandBuffer, Renderer.getCurrentImage()); +// } int result = vkEndCommandBuffer(commandBuffer); if(result != VK_SUCCESS) { diff --git a/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java b/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java index 53e4c29f3..b22b9dc8f 100644 --- a/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java +++ b/src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java @@ -21,6 +21,8 @@ import static org.lwjgl.vulkan.VK10.*; public class VulkanImage { + private static final int depthFormat = Device.findDepthFormat(); + private static final int defDepthAspect = !hasStencilComponent(depthFormat) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; public static int DefaultFormat = VK_FORMAT_R8G8B8A8_UNORM; private static VkDevice device = Vulkan.getDevice(); @@ -410,7 +412,7 @@ private void copyBufferToImageCmd(CommandPool.CommandBuffer commandBuffer, long region.imageSubresource().baseArrayLayer(0); region.imageSubresource().layerCount(1); region.imageOffset().set(xOffset, yOffset, 0); - region.imageExtent(VkExtent3D.calloc(stack).set(width, height, 1)); + region.imageExtent().set(width, height, 1); vkCmdCopyBufferToImage(commandBuffer.getHandle(), buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region); } @@ -431,7 +433,7 @@ private static void copyImageToBuffer(long buffer, long image, int mipLevel, int region.imageSubresource().baseArrayLayer(0); region.imageSubresource().layerCount(1); region.imageOffset().set(xOffset, yOffset, 0); - region.imageExtent(VkExtent3D.calloc(stack).set(width, height, 1)); + region.imageExtent().set(width, height, 1); vkCmdCopyImageToBuffer(commandBuffer.getHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, region); @@ -520,7 +522,7 @@ public static void transitionLayout(MemoryStack stack, VkCommandBuffer commandBu barrier.subresourceRange().layerCount(1); barrier.subresourceRange() - .aspectMask(image.format == VK_FORMAT_D32_SFLOAT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT); + .aspectMask(image.format == depthFormat ? defDepthAspect : VK_IMAGE_ASPECT_COLOR_BIT); barrier.srcAccessMask(srcAccessMask); barrier.dstAccessMask(dstAccessMask); From 937f2f4121592aa5e25c2041eb10c4343c227cf6 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Sat, 4 Nov 2023 18:29:55 +0000 Subject: [PATCH 4/8] Revert forcing clears to be depth only --- .../mixin/render/GameRendererMixin.java | 11 ++++ .../mixin/render/LevelRendererMixin.java | 8 +++ .../java/net/vulkanmod/vulkan/Renderer.java | 50 +++++++++++++++---- .../net/vulkanmod/vulkan/VRenderSystem.java | 2 +- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/vulkanmod/mixin/render/GameRendererMixin.java b/src/main/java/net/vulkanmod/mixin/render/GameRendererMixin.java index 7f5298e68..af70727f7 100644 --- a/src/main/java/net/vulkanmod/mixin/render/GameRendererMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/GameRendererMixin.java @@ -11,6 +11,8 @@ import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceProvider; +import net.vulkanmod.vulkan.Renderer; +import net.vulkanmod.vulkan.VRenderSystem; import net.vulkanmod.vulkan.memory.MemoryManager; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; @@ -19,6 +21,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.io.IOException; @@ -344,4 +347,12 @@ public void preloadUiShader(ResourceProvider resourceProvider) { } } +// @Redirect(method = "renderLevel", at = @At(value="INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V")) +// private void clear2hand(int i, boolean bl) { +// Renderer.clearAttachments(0x100); +// } + + @Redirect(method = "render", at = @At(value="INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V", ordinal = 0)) + private void remClear(int i, boolean bl) {} + } diff --git a/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java b/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java index 4b0d673f1..0d0f20eb6 100644 --- a/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java @@ -1,11 +1,14 @@ package net.vulkanmod.mixin.render; +import com.mojang.blaze3d.pipeline.RenderTarget; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.PostChain; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(LevelRenderer.class) public abstract class LevelRendererMixin { @@ -37,4 +40,9 @@ public void initOutline() { // this.entityOutlinesFramebuffer = null; // } } + + @Redirect(method = "renderLevel", at=@At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V")) + private void redirectClear2(int i, boolean bl) {} + @Redirect(method = "renderLevel", at=@At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;clear(Z)V")) + private void redirectClear(RenderTarget instance, boolean bl) {} } diff --git a/src/main/java/net/vulkanmod/vulkan/Renderer.java b/src/main/java/net/vulkanmod/vulkan/Renderer.java index 8353a1af9..542786634 100644 --- a/src/main/java/net/vulkanmod/vulkan/Renderer.java +++ b/src/main/java/net/vulkanmod/vulkan/Renderer.java @@ -16,6 +16,7 @@ import net.vulkanmod.vulkan.texture.VTextureSelector; import net.vulkanmod.vulkan.util.VUtil; import org.lwjgl.PointerBuffer; +import org.lwjgl.opengl.GL11C; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.*; @@ -27,6 +28,8 @@ import java.util.List; import java.util.Set; +import static com.mojang.blaze3d.platform.GlConst.GL_COLOR_BUFFER_BIT; +import static com.mojang.blaze3d.platform.GlConst.GL_DEPTH_BUFFER_BIT; import static net.vulkanmod.vulkan.Vulkan.*; import static org.lwjgl.system.MemoryStack.stackGet; import static org.lwjgl.system.MemoryStack.stackPush; @@ -487,21 +490,50 @@ public static void clearAttachments(int v) { if(framebuffer == null) return; - clearDepthAttachment(v, framebuffer.getWidth(), framebuffer.getHeight()); + clearAttachments(v, framebuffer.getWidth(), framebuffer.getHeight()); } - public static void clearDepthAttachment(int v, int width, int height) { - if(skipRendering || v == 0x4000 || v == 0x4100) + public static void clearAttachments(int v, int width, int height) { + if(skipRendering) return; try(MemoryStack stack = stackPush()) { //ClearValues have to be different for each attachment to clear, it seems it works like a buffer: color and depth attributes override themselves + VkClearValue colorValue = VkClearValue.calloc(stack); + colorValue.color().float32(VRenderSystem.clearColor); + + VkClearValue depthValue = VkClearValue.calloc(stack); + depthValue.depthStencil().set(VRenderSystem.clearDepth, 0); //Use fast depth clears if possible + + int attachmentsCount = v == (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) ? 2 : 1; + final VkClearAttachment.Buffer pAttachments = VkClearAttachment.malloc(attachmentsCount, stack); + switch (v) { + case GL_DEPTH_BUFFER_BIT -> { + + VkClearAttachment clearDepth = pAttachments.get(0); + clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); + clearDepth.clearValue(depthValue); + } + case GL_COLOR_BUFFER_BIT -> { - - VkClearAttachment.Buffer clearDepth = VkClearAttachment.malloc(1, stack); - clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); - clearDepth.clearValue().depthStencil().set(VRenderSystem.clearDepth, 0); - + VkClearAttachment clearColor = pAttachments.get(0); + clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT); + clearColor.colorAttachment(0); + clearColor.clearValue(colorValue); + } + case GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT -> { + + VkClearAttachment clearColor = pAttachments.get(0); + clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT); + clearColor.colorAttachment(0); + clearColor.clearValue(colorValue); + + VkClearAttachment clearDepth = pAttachments.get(1); + clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT); + clearDepth.clearValue(depthValue); + } + default -> throw new RuntimeException("unexpected value"); + } //Rect to clear VkRect2D renderArea = VkRect2D.malloc(stack); @@ -513,7 +545,7 @@ public static void clearDepthAttachment(int v, int width, int height) { pRect.baseArrayLayer(0); pRect.layerCount(1); - vkCmdClearAttachments(INSTANCE.currentCmdBuffer, clearDepth, pRect); + vkCmdClearAttachments(INSTANCE.currentCmdBuffer, pAttachments, pRect); } } diff --git a/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java b/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java index d6e3a6c96..71a409cf5 100644 --- a/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java +++ b/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java @@ -30,7 +30,7 @@ public class VRenderSystem { public static boolean cull = true; - public static float clearDepth = 1.0f; + public static final float clearDepth = 1.0f; public static FloatBuffer clearColor = MemoryUtil.memAllocFloat(4); public static MappedBuffer modelViewMatrix = new MappedBuffer(16 * 4); From 6aef636ed1a5fcd8bc1488f18e749145a0920c92 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Sun, 5 Nov 2023 15:18:48 +0000 Subject: [PATCH 5/8] Remove Swapchain Images option --- .../java/net/vulkanmod/config/Config.java | 1 - .../java/net/vulkanmod/config/Options.java | 32 +------------------ .../vulkan/framebuffer/SwapChain.java | 5 ++- 3 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/main/java/net/vulkanmod/config/Config.java b/src/main/java/net/vulkanmod/config/Config.java index 5fb6d8fcc..b4a3e67e1 100644 --- a/src/main/java/net/vulkanmod/config/Config.java +++ b/src/main/java/net/vulkanmod/config/Config.java @@ -13,7 +13,6 @@ public class Config { public int frameQueueSize = 2; - public int minImageCount = 3; public VideoResolution resolution = VideoResolution.getFirstAvailable(); public boolean windowedFullscreen = false; public boolean guiOptimizations = false; diff --git a/src/main/java/net/vulkanmod/config/Options.java b/src/main/java/net/vulkanmod/config/Options.java index 0504898e1..a320edc8f 100644 --- a/src/main/java/net/vulkanmod/config/Options.java +++ b/src/main/java/net/vulkanmod/config/Options.java @@ -16,23 +16,6 @@ public class Options { static Window window = Minecraft.getInstance().getWindow(); public static boolean fullscreenDirty = false; - private static final int minImages; - - private static final int maxImages; - - - static - { - try(MemoryStack stack = MemoryStack.stackPush()) - { - Device.SurfaceProperties surfaceProperties = Device.querySurfaceProperties(device.getPhysicalDevice(), stack); - minImages = surfaceProperties.capabilities.minImageCount(); - int maxImageCount = surfaceProperties.capabilities.maxImageCount(); - - boolean hasInfiniteSwapChain = maxImageCount == 0; //Applicable if Mesa/RADV Driver are present - maxImages = hasInfiniteSwapChain ? 64 : maxImageCount; - } - } public static Option[] getVideoOpts() { @@ -193,20 +176,7 @@ public static Option[] getOtherOpts() { config.frameQueueSize = value; Renderer.scheduleSwapChainUpdate(); }, () -> config.frameQueueSize) - .setTooltip(Component.nullToEmpty(""" - Manages the tradeoff between FPS and input lag - Most GPUs only require 2 for max performance - and usually don't have any performance benefits with 3 or higher""")), - new RangeOption("SwapChain Images", minImages, - maxImages, 1, - value -> { - config.minImageCount = value; - Renderer.scheduleSwapChainUpdate(); - }, () -> config.minImageCount) - .setTooltip(Component.nullToEmpty(""" - Sets the number of Swapchain images - Optimised automatically for best performance - This can be reduced to minimise input lag but at the cost of decreased FPS""")), + .setTooltip(Component.nullToEmpty("")), new SwitchOption("Gui Optimizations", value -> config.guiOptimizations = value, () -> config.guiOptimizations) diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java index 1a82d95f9..736992984 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java @@ -29,6 +29,7 @@ public class SwapChain extends Framebuffer { private static int DEFAULT_DEPTH_FORMAT = 0; + private static final int DEFAULT_IMAGE_COUNT = 3; public static int getDefaultDepthFormat() { return DEFAULT_DEPTH_FORMAT; @@ -101,10 +102,8 @@ public void createSwapChain() { return; } //minImageCount depends on driver: Mesa/RADV needs a min of 4, but most other drivers are at least 2 or 3 - if(Initializer.CONFIG.minImageCount < surfaceProperties.capabilities.minImageCount()) - Initializer.CONFIG.minImageCount = surfaceProperties.capabilities.minImageCount(); - int requestedFrames = Initializer.CONFIG.minImageCount; + int requestedFrames = Math.max(DEFAULT_IMAGE_COUNT, surfaceProperties.capabilities.minImageCount()); IntBuffer imageCount = stack.ints(requestedFrames); // IntBuffer imageCount = stack.ints(Math.max(surfaceProperties.capabilities.minImageCount(), preferredImageCount)); From 66bcb0a5382da2319f8e6af5288bf933b5d0ecc3 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Tue, 7 Nov 2023 19:47:55 +0000 Subject: [PATCH 6/8] Fix Segfault on Wayland when closing the client (i.e. Wayland is fussy about the order, and Window handle must be destroyed after the Swapchain and vkInstance, and not before) Rebase This reverts commit 7eb7a5f9c4f4ecb30efbd8bd4e7166c471c0cc04. Refactor Chunk rendering + Improve Draw Direct Performance Make PushConstants per ChunkArea instead of per RenderSection; Reduces PushConstant CPU usage by over 100x in DrawCall heavy scenarios Use compile time length for ChunkArea SectionQueues to improve JIT Optimisations Merge Direct/Indirect Shaders: Use same shader for both Direct and Draw Indirect + remove Indirect Pipeline Skip 0 index (i.e. empty draw calls) checks + reduce DescriptorSet binding Frequency Faster Gaussian Sky Blending [GPU Optimisation]: Separate VertexBuffers per RenderType Use Queue Enum + Split CommandPools based on Queue/Operation Type Dedicated Transfer Queue specific fixes Enable VK12 VMA Features Bizarrely Improves Performance by at least 15/20% according to initial testing Optimise Chunk Shader (May either have no performance improvement and/or have possible Shader/Visual artefacts) Early-Z Optimisations + Reduce AreaBuffer Fragmentation + Final Cleanup (Quick Summary) * Align Sizes to power of 2 * Reduce Pipeline Binding Frequency * Refactor ChunkTask to use RenderType enums to reduce CPU + * improve JIT optimisations * Try to use Early-Z on Translucent RenderType Fix Segfault on Wayland when closing the client (i.e. Wayland is fussy about the order, and Window handle must be destroyed after the Swapchain and vkInstance, and not before) Revert "Rebase" This reverts commit f0382e3b67df4282005f6b2190d7f77d41a3a7dd. --- .../java/net/vulkanmod/mixin/render/MinecraftMixin.java | 6 +++++- src/main/java/net/vulkanmod/vulkan/Renderer.java | 1 + src/main/java/net/vulkanmod/vulkan/Vulkan.java | 7 +++++-- .../java/net/vulkanmod/vulkan/framebuffer/RenderPass.java | 1 - .../net/vulkanmod/vulkan/texture/VTextureSelector.java | 6 ++++++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java b/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java index 9fec309cd..9b9a11169 100644 --- a/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java @@ -140,7 +140,11 @@ public void close(CallbackInfo ci) { Vulkan.waitIdle(); } - @Inject(method = "close", at = @At(value = "RETURN")) + /** + * @author + * @reason On Wayland the window (apparently) can only be safely destroyed after both SwapChain and VkInstance are Destroyed, and not before (Hence injecting at HEAD and not RETURN) + */ + @Inject(method = "close", at = @At(value = "HEAD")) public void close2(CallbackInfo ci) { Vulkan.cleanUp(); diff --git a/src/main/java/net/vulkanmod/vulkan/Renderer.java b/src/main/java/net/vulkanmod/vulkan/Renderer.java index 542786634..fc4fa47ab 100644 --- a/src/main/java/net/vulkanmod/vulkan/Renderer.java +++ b/src/main/java/net/vulkanmod/vulkan/Renderer.java @@ -426,6 +426,7 @@ public void cleanUpResources() { TerrainShaderManager.destroyPipelines(); VTextureSelector.getWhiteTexture().free(); + VTextureSelector.freeAll(); } private void destroySyncObjects() { diff --git a/src/main/java/net/vulkanmod/vulkan/Vulkan.java b/src/main/java/net/vulkanmod/vulkan/Vulkan.java index 07db5d752..24fe0733b 100644 --- a/src/main/java/net/vulkanmod/vulkan/Vulkan.java +++ b/src/main/java/net/vulkanmod/vulkan/Vulkan.java @@ -9,6 +9,7 @@ import net.vulkanmod.vulkan.queue.Queue; import net.vulkanmod.vulkan.queue.TransferQueue; import net.vulkanmod.vulkan.shader.Pipeline; +import net.vulkanmod.vulkan.texture.VTextureSelector; import net.vulkanmod.vulkan.texture.VulkanImage; import net.vulkanmod.vulkan.util.VUtil; import org.lwjgl.PointerBuffer; @@ -194,11 +195,13 @@ public static void cleanUp() { vkDestroyFence(Device.device, immediateFence, null); Pipeline.destroyPipelineCache(); +// WorldRenderer.getInstance().cleanUp(); + Renderer.getInstance().cleanUpResources(); + swapChain.getRenderPass().cleanUp(); swapChain.cleanUp(); - Renderer.getInstance().cleanUpResources(); freeStagingBuffers(); - +// VTextureSelector.freeAll(); try { MemoryManager.getInstance().freeAllBuffers(); } catch (Exception e) { diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java index b74045285..0fb4b590c 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java @@ -227,7 +227,6 @@ public long getId() { public static class AttachmentInfo { final Type type; final int format; - VulkanImage attachment; int initialLayout; int loadOp; int storeOp; diff --git a/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java b/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java index 2edd6d8f7..04983c6a3 100644 --- a/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java +++ b/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java @@ -86,4 +86,10 @@ public static VulkanImage getOverlayTexture() { public static VulkanImage getBoundTexture() { return boundTexture; } public static VulkanImage getWhiteTexture() { return whiteTexture; } + + public static void freeAll() + { + framebufferTexture.doFree(); + framebufferTexture2.doFree(); + } } From 5b86221df4676386d36ba1bfab10b48f665d8455 Mon Sep 17 00:00:00 2001 From: thr3343 <125277899+thr3343@users.noreply.github.com> Date: Sun, 12 Nov 2023 21:28:01 +0000 Subject: [PATCH 7/8] Enable VK12 VMA Features + Misc. Shader/Optimisation tweaks --- .../net/vulkanmod/render/chunk/ChunkArea.java | 4 +- .../vulkanmod/render/chunk/DrawBuffers.java | 98 +++++++----------- .../vulkanmod/render/chunk/WorldRenderer.java | 18 ++-- .../render/chunk/build/CompiledSection.java | 3 +- .../render/chunk/util/StaticQueue.java | 99 +++++++++++++++++++ .../java/net/vulkanmod/vulkan/Drawer.java | 3 +- .../java/net/vulkanmod/vulkan/Vulkan.java | 5 +- .../vulkan/framebuffer/Framebuffer.java | 2 +- .../vulkan/memory/AutoIndexBuffer.java | 4 +- .../net/vulkanmod/vulkan/shader/Pipeline.java | 2 +- .../vulkanmod/vulkan/shader/SPIRVUtils.java | 2 +- .../shader/descriptor/ImageDescriptor.java | 2 +- .../vulkanmod/shaders/include/light.glsl | 18 ++-- 13 files changed, 163 insertions(+), 97 deletions(-) create mode 100644 src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java diff --git a/src/main/java/net/vulkanmod/render/chunk/ChunkArea.java b/src/main/java/net/vulkanmod/render/chunk/ChunkArea.java index 39a35fbdf..228dfab7b 100644 --- a/src/main/java/net/vulkanmod/render/chunk/ChunkArea.java +++ b/src/main/java/net/vulkanmod/render/chunk/ChunkArea.java @@ -2,6 +2,7 @@ import net.minecraft.core.BlockPos; import net.vulkanmod.render.chunk.util.ResettableQueue; +import net.vulkanmod.render.chunk.util.StaticQueue; import org.joml.FrustumIntersection; import org.joml.Vector3i; @@ -15,7 +16,8 @@ public class ChunkArea { DrawBuffers drawBuffers; - final ResettableQueue sectionQueue = new ResettableQueue<>(); + //Help JIT optimisations by hardcoding the queue size to the max possible ChunkArea limit + final StaticQueue sectionQueue = new StaticQueue<>(512); public ChunkArea(int i, Vector3i origin) { this.index = i; diff --git a/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java b/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java index 580697713..55eee3196 100644 --- a/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java +++ b/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java @@ -3,6 +3,7 @@ import net.minecraft.client.renderer.RenderType; import net.vulkanmod.render.chunk.build.UploadBuffer; import net.vulkanmod.render.chunk.util.ResettableQueue; +import net.vulkanmod.render.chunk.util.StaticQueue; import net.vulkanmod.render.vertex.TerrainRenderType; import net.vulkanmod.vulkan.Renderer; import net.vulkanmod.vulkan.memory.IndirectBuffer; @@ -60,7 +61,7 @@ public DrawParameters upload(UploadBuffer buffer, DrawParameters drawParameters) drawParameters.firstIndex = firstIndex; drawParameters.vertexOffset = vertexOffset; - Renderer.getDrawer().getQuadsIndexBuffer().checkCapacity(buffer.indexCount * 2 / 3); + buffer.release(); @@ -72,7 +73,7 @@ public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, ChunkArea chu int drawCount = 0; - ResettableQueue queue = chunkArea.sectionQueue; + StaticQueue queue = chunkArea.sectionQueue; MemoryStack stack = MemoryStack.stackPush(); ByteBuffer byteBuffer = stack.calloc(20 * queue.size()); @@ -86,8 +87,9 @@ public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, ChunkArea chu Pipeline pipeline = TerrainShaderManager.getTerrainIndirectShader(renderType); + VkCommandBuffer commandBuffer = Renderer.getCommandBuffer(); if(isTranslucent) { - vkCmdBindIndexBuffer(Renderer.getCommandBuffer(), this.indexBuffer.getId(), 0, VK_INDEX_TYPE_UINT16); + vkCmdBindIndexBuffer(commandBuffer, this.indexBuffer.getId(), 0, VK_INDEX_TYPE_UINT16); } var iterator = queue.iterator(isTranslucent); @@ -110,10 +112,6 @@ public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, ChunkArea chu // } - if(drawParameters.indexCount == 0) { - continue; - } - //TODO if(!drawParameters.ready && drawParameters.vertexBufferSegment.getOffset() != -1) { if(!drawParameters.vertexBufferSegment.isReady()) @@ -152,11 +150,11 @@ public int buildDrawBatchesIndirect(IndirectBuffer indirectBuffer, ChunkArea chu LongBuffer pVertexBuffer = stack.longs(vertexBuffer.getId()); LongBuffer pOffset = stack.longs(0); - vkCmdBindVertexBuffers(Renderer.getCommandBuffer(), 0, pVertexBuffer, pOffset); + vkCmdBindVertexBuffers(commandBuffer, 0, pVertexBuffer, pOffset); // pipeline.bindDescriptorSets(Drawer.getCommandBuffer(), WorldRenderer.getInstance().getUniformBuffers(), Drawer.getCurrentFrame()); - pipeline.bindDescriptorSets(Renderer.getCommandBuffer(), Renderer.getCurrentFrame()); - vkCmdDrawIndexedIndirect(Renderer.getCommandBuffer(), indirectBuffer.getId(), indirectBuffer.getOffset(), drawCount, stride); + pipeline.bindDescriptorSets(commandBuffer, Renderer.getCurrentFrame()); + vkCmdDrawIndexedIndirect(commandBuffer, indirectBuffer.getId(), indirectBuffer.getOffset(), drawCount, stride); // fakeIndirectCmd(Drawer.getCommandBuffer(), indirectBuffer, drawCount, uboBuffer); @@ -202,82 +200,54 @@ private static void fakeIndirectCmd(VkCommandBuffer commandBuffer, IndirectBuffe } } - public void buildDrawBatchesDirect(ResettableQueue queue, Pipeline pipeline, RenderType renderType, double camX, double camY, double camZ) { + public void buildDrawBatchesDirect(StaticQueue queue, Pipeline pipeline, RenderType renderType, double camX, double camY, double camZ) { TerrainRenderType terrainRenderType = TerrainRenderType.get(renderType); terrainRenderType.setCutoutUniform(); boolean isTranslucent = terrainRenderType == TerrainRenderType.TRANSLUCENT; - try(MemoryStack stack = MemoryStack.stackPush()) { - LongBuffer pVertexBuffer = stack.longs(vertexBuffer.getId()); - LongBuffer pOffset = stack.longs(0); - vkCmdBindVertexBuffers(Renderer.getCommandBuffer(), 0, pVertexBuffer, pOffset); - - } - - if(isTranslucent) { - vkCmdBindIndexBuffer(Renderer.getCommandBuffer(), this.indexBuffer.getId(), 0, VK_INDEX_TYPE_UINT16); - } - VkCommandBuffer commandBuffer = Renderer.getCommandBuffer(); + try(MemoryStack stack = MemoryStack.stackPush()) { + long pVertexBuffer = stack.npointer(vertexBuffer.getId()); + long pOffset = stack.npointer(0); + nvkCmdBindVertexBuffers(commandBuffer, 0, 1, (pVertexBuffer), (pOffset)); -// Pipeline pipeline = ShaderManager.shaderManager.terrainDirectShader; -// Pipeline pipeline = TestShaders.getShaderPipeline(renderType); -// Drawer.getInstance().bindPipeline(pipeline); - pipeline.bindDescriptorSets(Renderer.getCommandBuffer(), Renderer.getCurrentFrame()); -// ResettableQueue queue = chunkArea.sectionQueue; - int drawCount = 0; - MemoryStack stack = MemoryStack.stackGet().push(); - ByteBuffer byteBuffer = stack.malloc(24 * queue.size()); - long bufferPtr = MemoryUtil.memAddress0(byteBuffer); + if(isTranslucent) { + vkCmdBindIndexBuffer(commandBuffer, this.indexBuffer.getId(), 0, VK_INDEX_TYPE_UINT16); + } - var iterator = queue.iterator(isTranslucent); - while (iterator.hasNext()) { - RenderSection section = iterator.next(); - DrawParameters drawParameters = section.getDrawParameters(terrainRenderType); - if(drawParameters.indexCount == 0) { - continue; - } - long ptr = bufferPtr + (drawCount * 24L); - MemoryUtil.memPutInt(ptr, drawParameters.indexCount); - MemoryUtil.memPutInt(ptr + 4, drawParameters.firstIndex); - MemoryUtil.memPutInt(ptr + 8, drawParameters.vertexOffset); + // Pipeline pipeline = ShaderManager.shaderManager.terrainDirectShader; + // Pipeline pipeline = TestShaders.getShaderPipeline(renderType); + // Drawer.getInstance().bindPipeline(pipeline); + pipeline.bindDescriptorSets(commandBuffer, Renderer.getCurrentFrame()); - MemoryUtil.memPutFloat(ptr + 12, (float)((double) section.xOffset - camX)); - MemoryUtil.memPutFloat(ptr + 16, (float)((double) section.yOffset - camY)); - MemoryUtil.memPutFloat(ptr + 20, (float)((double) section.zOffset - camZ)); + // ResettableQueue queue = chunkArea.sectionQueue; - drawCount++; - } + final long ptr = stack.nmalloc(16); + final long layout = pipeline.getLayout(); + final float camX1 = (float) camX; + final float camY1 = (float) camY; + final float camZ1 = (float) camZ; - if(drawCount > 0) { - long offset; - int indexCount; - int firstIndex; - int vertexOffset; - for(int i = 0; i < drawCount; ++i) { + for (var iterator = queue.iterator(isTranslucent); iterator.hasNext(); ) { + RenderSection section = iterator.next(); + DrawParameters drawParameters = section.getDrawParameters(terrainRenderType); - offset = i * 24 + bufferPtr; - indexCount = MemoryUtil.memGetInt(offset + 0); - firstIndex = MemoryUtil.memGetInt(offset + 4); - vertexOffset = MemoryUtil.memGetInt(offset + 8); + MemoryUtil.memPutFloat(ptr + 0, section.xOffset - camX1); + MemoryUtil.memPutFloat(ptr + 4, section.yOffset - camY1); + MemoryUtil.memPutFloat(ptr + 8, section.zOffset - camZ1); -// if(indexCount == 0) { -// continue; -// } + nvkCmdPushConstants(commandBuffer, layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 12, ptr); - nvkCmdPushConstants(commandBuffer, pipeline.getLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 12, offset + 12); + vkCmdDrawIndexed(commandBuffer, drawParameters.indexCount, 1, drawParameters.firstIndex, drawParameters.vertexOffset, 0); - vkCmdDrawIndexed(commandBuffer, indexCount, 1, firstIndex, vertexOffset, 0); } } - - stack.pop(); } public void releaseBuffers() { diff --git a/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java b/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java index 993ffcd3c..5d786c5ce 100644 --- a/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java +++ b/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java @@ -314,9 +314,9 @@ private void updateRenderChunks() { while(this.chunkQueue.hasNext()) { RenderSection renderSection = this.chunkQueue.poll(); - renderSection.getChunkArea().sectionQueue.add(renderSection); if(!renderSection.isCompletelyEmpty()) { + renderSection.getChunkArea().sectionQueue.add(renderSection); this.chunkAreaQueue.add(renderSection.getChunkArea()); this.nonEmptyChunks++; } @@ -355,9 +355,9 @@ private void updateRenderChunksSpectator() { while(this.chunkQueue.hasNext()) { RenderSection renderSection = this.chunkQueue.poll(); - renderSection.getChunkArea().sectionQueue.add(renderSection); if(!renderSection.isCompletelyEmpty()) { + renderSection.getChunkArea().sectionQueue.add(renderSection); this.chunkAreaQueue.add(renderSection.getChunkArea()); this.nonEmptyChunks++; } @@ -577,20 +577,14 @@ else if(layerName.equals("translucent")) p.push("draw batches"); - ObjectArrayList renderTypes; - if(Initializer.CONFIG.uniqueOpaqueLayer) { - renderTypes = TerrainRenderType.COMPACT_RENDER_TYPES; - } else { - renderTypes = TerrainRenderType.SEMI_COMPACT_RENDER_TYPES; - } - - if(renderTypes.contains(renderType)) { + int currentFrame = Renderer.getCurrentFrame(); + if((Initializer.CONFIG.uniqueOpaqueLayer ? TerrainRenderType.COMPACT_RENDER_TYPES : TerrainRenderType.SEMI_COMPACT_RENDER_TYPES).contains(renderType)) { Iterator iterator = this.chunkAreaQueue.iterator(flag); while(iterator.hasNext()) { ChunkArea chunkArea = iterator.next(); if(indirectDraw) { - chunkArea.getDrawBuffers().buildDrawBatchesIndirect(indirectBuffers[Renderer.getCurrentFrame()], chunkArea, renderType, camX, camY, camZ); + chunkArea.getDrawBuffers().buildDrawBatchesIndirect(indirectBuffers[currentFrame], chunkArea, renderType, camX, camY, camZ); } else { chunkArea.getDrawBuffers().buildDrawBatchesDirect(chunkArea.sectionQueue, pipeline, renderType, camX, camY, camZ); } @@ -598,7 +592,7 @@ else if(layerName.equals("translucent")) } if(layerName.equals("cutout") || layerName.equals("tripwire")) { - indirectBuffers[Renderer.getCurrentFrame()].submitUploads(); + indirectBuffers[currentFrame].submitUploads(); // uniformBuffers.submitUploads(); } p.pop(); diff --git a/src/main/java/net/vulkanmod/render/chunk/build/CompiledSection.java b/src/main/java/net/vulkanmod/render/chunk/build/CompiledSection.java index 4711ac17d..b132b87e0 100644 --- a/src/main/java/net/vulkanmod/render/chunk/build/CompiledSection.java +++ b/src/main/java/net/vulkanmod/render/chunk/build/CompiledSection.java @@ -9,6 +9,7 @@ import net.vulkanmod.render.vertex.TerrainRenderType; import javax.annotation.Nullable; +import java.util.EnumSet; import java.util.List; import java.util.Set; @@ -18,7 +19,7 @@ public boolean canSeeThrough(Direction dir1, Direction dir2) { return false; } }; - public final Set renderTypes = new ObjectArraySet<>(); + public final Set renderTypes = EnumSet.noneOf(TerrainRenderType.class); boolean isCompletelyEmpty = true; final List renderableBlockEntities = Lists.newArrayList(); VisibilitySet visibilitySet = new VisibilitySet(); diff --git a/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java b/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java new file mode 100644 index 000000000..b355b87fe --- /dev/null +++ b/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java @@ -0,0 +1,99 @@ +package net.vulkanmod.render.chunk.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; +import java.util.function.Consumer; + +public class StaticQueue implements Iterable { + final T[] queue; + int position = 0; + int limit = 0; + final int capacity; + + public StaticQueue() { + this(1024); + } + + @SuppressWarnings("unchecked") + public StaticQueue(int initialCapacity) { + this.capacity = initialCapacity; + + this.queue = (T[])(new Object[capacity]); + } + + public boolean hasNext() { + return this.position < this.limit; + } + + public T poll() { + T t = this.queue[position]; + this.position++; + + return t; + } + + public void add(T t) { + if(t == null) + return; + + if(limit == capacity) throw new RuntimeException("Exceeded size: "+this.capacity); + this.queue[limit] = t; + + this.limit++; + } + + public int size() { + return limit; + } + + public void clear() { + this.position = 0; + this.limit = 0; + } + + public Iterator iterator(boolean reverseOrder) { + return reverseOrder ? new Iterator<>() { + int pos = StaticQueue.this.limit - 1; + final int limit = -1; + + @Override + public boolean hasNext() { + return pos > limit; + } + + @Override + public T next() { + return queue[pos--]; + } + } + : new Iterator<>() { + int pos = 0; + final int limit = StaticQueue.this.limit; + + @Override + public boolean hasNext() { + return pos < limit; + } + + @Override + public T next() { + return queue[pos++]; + } + }; + } + + @NotNull + @Override + public Iterator iterator() { + return iterator(false); + } + + @Override + public void forEach(Consumer action) { + for(int i = 0; i < this.limit; ++i) { + action.accept(this.queue[i]); + } + + } +} diff --git a/src/main/java/net/vulkanmod/vulkan/Drawer.java b/src/main/java/net/vulkanmod/vulkan/Drawer.java index cecef9534..b5aa806f1 100644 --- a/src/main/java/net/vulkanmod/vulkan/Drawer.java +++ b/src/main/java/net/vulkanmod/vulkan/Drawer.java @@ -22,6 +22,7 @@ public class Drawer { private static final LongBuffer offsets = MemoryUtil.memAllocLong(1); private static final long pBuffers = MemoryUtil.memAddress0(buffers); private static final long pOffsets = MemoryUtil.memAddress0(offsets); + private static final int UINT16_INDEX_MAX = 98304; private int framesNum; private VertexBuffer[] vertexBuffers; @@ -34,7 +35,7 @@ public class Drawer { public Drawer() { //Index buffers - quadsIndexBuffer = new AutoIndexBuffer(100000, AutoIndexBuffer.DrawType.QUADS); + quadsIndexBuffer = new AutoIndexBuffer(UINT16_INDEX_MAX, AutoIndexBuffer.DrawType.QUADS); triangleFanIndexBuffer = new AutoIndexBuffer(1000, AutoIndexBuffer.DrawType.TRIANGLE_FAN); triangleStripIndexBuffer = new AutoIndexBuffer(1000, AutoIndexBuffer.DrawType.TRIANGLE_STRIP); } diff --git a/src/main/java/net/vulkanmod/vulkan/Vulkan.java b/src/main/java/net/vulkanmod/vulkan/Vulkan.java index 24fe0733b..609d66adb 100644 --- a/src/main/java/net/vulkanmod/vulkan/Vulkan.java +++ b/src/main/java/net/vulkanmod/vulkan/Vulkan.java @@ -236,9 +236,9 @@ private static void createInstance() { appInfo.sType(VK_STRUCTURE_TYPE_APPLICATION_INFO); appInfo.pApplicationName(stack.UTF8Safe("VulkanMod")); - appInfo.applicationVersion(VK_MAKE_VERSION(1, 0, 0)); + appInfo.applicationVersion(VK_API_VERSION_1_2); appInfo.pEngineName(stack.UTF8Safe("No Engine")); - appInfo.engineVersion(VK_MAKE_VERSION(1, 0, 0)); + appInfo.engineVersion(VK_API_VERSION_1_2); appInfo.apiVersion(VK_API_VERSION_1_2); VkInstanceCreateInfo createInfo = VkInstanceCreateInfo.calloc(stack); @@ -345,6 +345,7 @@ private static void createVma() { allocatorCreateInfo.device(Device.device); allocatorCreateInfo.pVulkanFunctions(vulkanFunctions); allocatorCreateInfo.instance(instance); + allocatorCreateInfo.vulkanApiVersion(VK_API_VERSION_1_2); PointerBuffer pAllocator = stack.pointers(VK_NULL_HANDLE); diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java index 421a000a9..7475a55a4 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java @@ -71,7 +71,7 @@ public void addRenderPass(RenderPass renderPass) { public void createImages() { if(this.hasColorAttachment) { this.colorAttachment = VulkanImage.createTextureImage(format, 1, width, height, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, linearFiltering, true); } diff --git a/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java index 48619fb1b..523a4ba38 100644 --- a/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java +++ b/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java @@ -5,6 +5,8 @@ import java.nio.ByteBuffer; import java.nio.ShortBuffer; +import static net.vulkanmod.vulkan.memory.AutoIndexBuffer.DrawType.QUADS; + public class AutoIndexBuffer { int vertexCount; DrawType drawType; @@ -44,7 +46,7 @@ private void createIndexBuffer(int vertexCount) { } public void checkCapacity(int vertexCount) { - if(vertexCount > this.vertexCount) { + if(this.drawType!=QUADS && vertexCount > this.vertexCount) { int newVertexCount = this.vertexCount * 2; System.out.println("Reallocating AutoIndexBuffer from " + this.vertexCount + " to " + newVertexCount); diff --git a/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java index 8160437a5..48dd112f2 100644 --- a/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java +++ b/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java @@ -599,7 +599,7 @@ public static int getStageFromString(String s) { return switch (s) { case "vertex" -> VK_SHADER_STAGE_VERTEX_BIT; case "fragment" -> VK_SHADER_STAGE_FRAGMENT_BIT; - case "all" -> VK_SHADER_STAGE_ALL_GRAPHICS; + case "all" -> VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT; case "compute" -> VK_SHADER_STAGE_COMPUTE_BIT; default -> throw new RuntimeException("cannot identify type.."); diff --git a/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java b/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java index 259e2eca3..f1d8001e6 100644 --- a/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java +++ b/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java @@ -25,7 +25,7 @@ public class SPIRVUtils { private static final boolean DEBUG = false; - private static final boolean OPTIMIZATIONS = false; + private static final boolean OPTIMIZATIONS = true; private static long compiler; private static long options; diff --git a/src/main/java/net/vulkanmod/vulkan/shader/descriptor/ImageDescriptor.java b/src/main/java/net/vulkanmod/vulkan/shader/descriptor/ImageDescriptor.java index 3718d35e5..2094bfc43 100644 --- a/src/main/java/net/vulkanmod/vulkan/shader/descriptor/ImageDescriptor.java +++ b/src/main/java/net/vulkanmod/vulkan/shader/descriptor/ImageDescriptor.java @@ -35,6 +35,6 @@ public int getType() { @Override public int getStages() { - return VK_SHADER_STAGE_ALL_GRAPHICS | VK_SHADER_STAGE_COMPUTE_BIT; + return VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; } } diff --git a/src/main/resources/assets/vulkanmod/shaders/include/light.glsl b/src/main/resources/assets/vulkanmod/shaders/include/light.glsl index 5876db958..b5a0decd9 100644 --- a/src/main/resources/assets/vulkanmod/shaders/include/light.glsl +++ b/src/main/resources/assets/vulkanmod/shaders/include/light.glsl @@ -1,29 +1,25 @@ //light.glsl -#define MINECRAFT_LIGHT_POWER (0.6) -#define MINECRAFT_AMBIENT_LIGHT (0.4) +//#pragma once +const float MINECRAFT_LIGHT_POWER = (0.6); +const float MINECRAFT_AMBIENT_LIGHT = (0.4); vec4 minecraft_mix_light(vec3 lightDir0, vec3 lightDir1, vec3 normal, vec4 color) { lightDir0 = normalize(lightDir0); lightDir1 = normalize(lightDir1); float light0 = max(0.0, dot(lightDir0, normal)); float light1 = max(0.0, dot(lightDir1, normal)); - float lightAccum = min(1.0, (light0 + light1) * MINECRAFT_LIGHT_POWER + MINECRAFT_AMBIENT_LIGHT); + float lightAccum = min(1.0, fma((light0 + light1), MINECRAFT_LIGHT_POWER, MINECRAFT_AMBIENT_LIGHT)); return vec4(color.rgb * lightAccum, color.a); } vec4 minecraft_sample_lightmap(sampler2D lightMap, ivec2 uv) { - return texture(lightMap, clamp(uv / 256.0, vec2(0.5 / 16.0), vec2(15.5 / 16.0))); + return texelFetch(lightMap, bitfieldExtract(uv, 4, 8), 0); //return texture(lightMap, clamp(uv / 256.0, vec2(0.5 / 16.0), vec2(15.5 / 16.0))); } vec4 sample_lightmap(sampler2D lightMap, ivec2 uv) { - return texelFetch(lightMap, (uv & 255) >> 4, 0); + return texelFetch(lightMap, bitfieldExtract(uv, 4, 8), 0); } vec4 linear_fog(vec4 inColor, float vertexDistance, float fogStart, float fogEnd, vec4 fogColor) { - if (vertexDistance <= fogStart) { - return inColor; - } - - float fogValue = vertexDistance < fogEnd ? smoothstep(fogStart, fogEnd, vertexDistance) : 1.0; - return vec4(mix(inColor.rgb, fogColor.rgb, fogValue * fogColor.a), inColor.a); + return (vertexDistance <= fogStart) ? inColor : mix(inColor, fogColor, min(smoothstep(fogStart, fogEnd, vertexDistance), 1.0) * fogColor.a); } \ No newline at end of file From 6d7487cb8ffd423e1a321f5b1ffe517d29c4931f Mon Sep 17 00:00:00 2001 From: xCollateral <> Date: Fri, 17 Nov 2023 12:42:12 +0100 Subject: [PATCH 8/8] Clean up + Minor fixes --- .../java/net/vulkanmod/config/Options.java | 10 ++-- .../mixin/render/LevelRendererMixin.java | 1 + .../mixin/render/MinecraftMixin.java | 59 +------------------ .../mixin/{ => wayland}/InputConstantsM.java | 5 +- .../mixin/wayland/MinecraftMixin.java | 38 ++++++++++++ .../render/chunk/AreaUploadManager.java | 2 +- .../vulkanmod/render/chunk/DrawBuffers.java | 57 ++++++++++++------ .../vulkanmod/render/chunk/WorldRenderer.java | 4 +- .../java/net/vulkanmod/vulkan/Renderer.java | 58 +++++++++--------- .../java/net/vulkanmod/vulkan/Vulkan.java | 35 ++++------- .../vulkan/framebuffer/Framebuffer.java | 2 +- .../vulkan/framebuffer/SwapChain.java | 24 +++----- .../vulkan/memory/AutoIndexBuffer.java | 4 +- .../vulkan/memory/UniformBuffers.java | 2 +- .../vulkan/shader/GraphicsPipeline.java | 2 +- .../net/vulkanmod/vulkan/shader/Pipeline.java | 2 +- .../vulkan/texture/VTextureSelector.java | 5 -- src/main/resources/vulkanmod.mixins.json | 17 +++++- 18 files changed, 160 insertions(+), 167 deletions(-) rename src/main/java/net/vulkanmod/mixin/{ => wayland}/InputConstantsM.java (83%) create mode 100644 src/main/java/net/vulkanmod/mixin/wayland/MinecraftMixin.java diff --git a/src/main/java/net/vulkanmod/config/Options.java b/src/main/java/net/vulkanmod/config/Options.java index a320edc8f..45421ece9 100644 --- a/src/main/java/net/vulkanmod/config/Options.java +++ b/src/main/java/net/vulkanmod/config/Options.java @@ -16,8 +16,6 @@ public class Options { static Window window = Minecraft.getInstance().getWindow(); public static boolean fullscreenDirty = false; - - public static Option[] getVideoOpts() { return new Option[] { new CyclingOption<>("Resolution", @@ -170,13 +168,15 @@ public static Option[] getGraphicsOpts() { public static Option[] getOtherOpts() { return new Option[] { - new RangeOption("Queue Frames", 1, + new RangeOption("Render queue size", 2, 5, 1, value -> { config.frameQueueSize = value; Renderer.scheduleSwapChainUpdate(); }, () -> config.frameQueueSize) - .setTooltip(Component.nullToEmpty("")), + .setTooltip(Component.nullToEmpty(""" + Higher values might help stabilize frametime + but will increase input lag""")), new SwitchOption("Gui Optimizations", value -> config.guiOptimizations = value, () -> config.guiOptimizations) @@ -206,7 +206,7 @@ Enable Gui optimizations (Stats bar, Chat, Debug Hud) value -> config.entityCulling = value, () -> config.entityCulling) .setTooltip(Component.nullToEmpty(""" - Enables culling for entities on non visible sections.""")), + Enables culling for entities on not visible sections.""")), new SwitchOption("Indirect Draw", value -> config.indirectDraw = value, () -> config.indirectDraw) diff --git a/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java b/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java index 0d0f20eb6..e22bdd627 100644 --- a/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/LevelRendererMixin.java @@ -43,6 +43,7 @@ public void initOutline() { @Redirect(method = "renderLevel", at=@At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V")) private void redirectClear2(int i, boolean bl) {} + @Redirect(method = "renderLevel", at=@At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;clear(Z)V")) private void redirectClear(RenderTarget instance, boolean bl) {} } diff --git a/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java b/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java index 9b9a11169..670ff1615 100644 --- a/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java +++ b/src/main/java/net/vulkanmod/mixin/render/MinecraftMixin.java @@ -1,38 +1,19 @@ package net.vulkanmod.mixin.render; import com.mojang.blaze3d.pipeline.RenderTarget; -import com.mojang.blaze3d.platform.IconSet; import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.TimerQuery; -import net.minecraft.SharedConstants; import net.minecraft.Util; import net.minecraft.client.GraphicsStatus; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; -import net.minecraft.client.gui.font.FontManager; import net.minecraft.client.main.GameConfig; -import net.minecraft.client.particle.ParticleEngine; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.VirtualScreen; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.resources.MobEffectTextureManager; -import net.minecraft.client.resources.PaintingTextureManager; -import net.minecraft.client.resources.model.ModelManager; -import net.minecraft.client.sounds.SoundManager; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.VanillaPackResources; -import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.vulkanmod.Initializer; -import net.vulkanmod.config.VideoResolution; -import net.vulkanmod.render.profiling.Profiler2; import net.vulkanmod.render.texture.SpriteUtil; import net.vulkanmod.vulkan.Renderer; import net.vulkanmod.vulkan.Vulkan; -import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -41,25 +22,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import java.io.IOException; import java.util.Optional; @Mixin(Minecraft.class) public class MinecraftMixin { - @Shadow @Final public ParticleEngine particleEngine; - @Shadow @Final public GameRenderer gameRenderer; - @Shadow @Final private ReloadableResourceManager resourceManager; - @Shadow @Final private FontManager fontManager; - @Shadow @Final private ModelManager modelManager; - @Shadow @Final private SoundManager soundManager; - @Shadow @Final private TextureManager textureManager; - @Shadow @Final private VirtualScreen virtualScreen; - @Shadow @Final private Window window; - @Shadow @Final private static Logger LOGGER; - @Shadow @Final public LevelRenderer levelRenderer; - @Shadow @Final private MobEffectTextureManager mobEffectTextures; - @Shadow @Final private PaintingTextureManager paintingTextures; @Shadow public boolean noRender; @Shadow @Final public Options options; @@ -73,8 +40,6 @@ private void forceGraphicsMode(GameConfig gameConfig, CallbackInfo ci) { } } - @Shadow @Final private VanillaPackResources vanillaPackResources; - @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V")) private void beginRender(int i, boolean bl) { Renderer.getInstance().beginFrame(); @@ -84,17 +49,6 @@ private void beginRender(int i, boolean bl) { private void submitRender(boolean tick, CallbackInfo ci) { Renderer.getInstance().endFrame(); } - /** - * @author - * @reason Only KWin supports setting the Icon on Wayland AFAIK - */ - @Redirect(method="", at=@At(value="INVOKE", target="Lcom/mojang/blaze3d/platform/Window;setIcon(Lnet/minecraft/server/packs/PackResources;Lcom/mojang/blaze3d/platform/IconSet;)V")) - private void bypassWaylandIcon(Window instance, PackResources packResources, IconSet iconSet) throws IOException { - if(!VideoResolution.isWayLand()) - { - this.window.setIcon(this.vanillaPackResources, SharedConstants.getCurrentVersion().isStable() ? IconSet.RELEASE : IconSet.SNAPSHOT); - } - } @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;bindWrite(Z)V")) private void redirectMainTarget1(RenderTarget instance, boolean bl) { @@ -134,23 +88,16 @@ private void resetBuffers(boolean bl, CallbackInfo ci) { Renderer.getInstance().resetBuffers(); } - @Inject(method = "close", at = @At(value = "HEAD")) public void close(CallbackInfo ci) { Vulkan.waitIdle(); - } - /** - * @author - * @reason On Wayland the window (apparently) can only be safely destroyed after both SwapChain and VkInstance are Destroyed, and not before (Hence injecting at HEAD and not RETURN) - */ - @Inject(method = "close", at = @At(value = "HEAD")) - public void close2(CallbackInfo ci) { - Vulkan.cleanUp(); + @Inject(method = "close", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/VirtualScreen;close()V")) + public void close2(CallbackInfo ci) { + Vulkan.cleanUp(); Util.shutdownExecutors(); - } @Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;emergencySave()V")) diff --git a/src/main/java/net/vulkanmod/mixin/InputConstantsM.java b/src/main/java/net/vulkanmod/mixin/wayland/InputConstantsM.java similarity index 83% rename from src/main/java/net/vulkanmod/mixin/InputConstantsM.java rename to src/main/java/net/vulkanmod/mixin/wayland/InputConstantsM.java index f0c27aafd..20ed6e104 100644 --- a/src/main/java/net/vulkanmod/mixin/InputConstantsM.java +++ b/src/main/java/net/vulkanmod/mixin/wayland/InputConstantsM.java @@ -1,4 +1,4 @@ -package net.vulkanmod.mixin; +package net.vulkanmod.mixin.wayland; import com.mojang.blaze3d.platform.InputConstants; import net.vulkanmod.config.VideoResolution; @@ -16,7 +16,8 @@ public class InputConstantsM { */ @Overwrite public static void grabOrReleaseMouse(long l, int i, double d, double e) { - if (!VideoResolution.isWayLand()) GLFW.glfwSetCursorPos(l, d, e); + if (!VideoResolution.isWayLand()) + GLFW.glfwSetCursorPos(l, d, e); GLFW.glfwSetInputMode(l, 208897, i); } } \ No newline at end of file diff --git a/src/main/java/net/vulkanmod/mixin/wayland/MinecraftMixin.java b/src/main/java/net/vulkanmod/mixin/wayland/MinecraftMixin.java new file mode 100644 index 000000000..d164cb9e9 --- /dev/null +++ b/src/main/java/net/vulkanmod/mixin/wayland/MinecraftMixin.java @@ -0,0 +1,38 @@ +package net.vulkanmod.mixin.wayland; + +import com.mojang.blaze3d.platform.IconSet; +import com.mojang.blaze3d.platform.Window; +import net.minecraft.SharedConstants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.VanillaPackResources; +import net.vulkanmod.config.VideoResolution; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.io.IOException; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow @Final private Window window; + @Shadow @Final public Options options; + + @Shadow @Final private VanillaPackResources vanillaPackResources; + + /** + * @author + * @reason Only KWin supports setting the Icon on Wayland AFAIK + */ + @Redirect(method="", at=@At(value="INVOKE", target="Lcom/mojang/blaze3d/platform/Window;setIcon(Lnet/minecraft/server/packs/PackResources;Lcom/mojang/blaze3d/platform/IconSet;)V")) + private void bypassWaylandIcon(Window instance, PackResources packResources, IconSet iconSet) throws IOException { + if(!VideoResolution.isWayLand()) + { + this.window.setIcon(this.vanillaPackResources, SharedConstants.getCurrentVersion().isStable() ? IconSet.RELEASE : IconSet.SNAPSHOT); + } + } +} diff --git a/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java b/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java index 4940e621d..490469ab7 100644 --- a/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java +++ b/src/main/java/net/vulkanmod/render/chunk/AreaUploadManager.java @@ -83,7 +83,7 @@ public void uploadAsync(AreaBuffer.Segment uploadSegment, long bufferId, long ds } public void updateFrame() { - this.currentFrame ^= this.currentFrame; + this.currentFrame = (this.currentFrame + 1) % FRAME_NUM; waitUploads(this.currentFrame); this.dstBuffers.clear(); diff --git a/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java b/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java index 55eee3196..092da49a3 100644 --- a/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java +++ b/src/main/java/net/vulkanmod/render/chunk/DrawBuffers.java @@ -217,36 +217,57 @@ public void buildDrawBatchesDirect(StaticQueue queue, Pipeline pi vkCmdBindIndexBuffer(commandBuffer, this.indexBuffer.getId(), 0, VK_INDEX_TYPE_UINT16); } + pipeline.bindDescriptorSets(commandBuffer, Renderer.getCurrentFrame()); + int drawCount = 0; + ByteBuffer byteBuffer = stack.malloc(24 * queue.size()); + long bufferPtr = MemoryUtil.memAddress0(byteBuffer); - // Pipeline pipeline = ShaderManager.shaderManager.terrainDirectShader; - // Pipeline pipeline = TestShaders.getShaderPipeline(renderType); - // Drawer.getInstance().bindPipeline(pipeline); - pipeline.bindDescriptorSets(commandBuffer, Renderer.getCurrentFrame()); + var iterator = queue.iterator(isTranslucent); + while (iterator.hasNext()) { + RenderSection section = iterator.next(); + DrawParameters drawParameters = section.getDrawParameters(terrainRenderType); - // ResettableQueue queue = chunkArea.sectionQueue; + if(drawParameters.indexCount == 0) { + continue; + } + long ptr = bufferPtr + (drawCount * 24L); + MemoryUtil.memPutInt(ptr, drawParameters.indexCount); + MemoryUtil.memPutInt(ptr + 4, drawParameters.firstIndex); + MemoryUtil.memPutInt(ptr + 8, drawParameters.vertexOffset); - final long ptr = stack.nmalloc(16); - final long layout = pipeline.getLayout(); - final float camX1 = (float) camX; - final float camY1 = (float) camY; - final float camZ1 = (float) camZ; + MemoryUtil.memPutFloat(ptr + 12, (float)((double) section.xOffset - camX)); + MemoryUtil.memPutFloat(ptr + 16, (float)((double) section.yOffset - camY)); + MemoryUtil.memPutFloat(ptr + 20, (float)((double) section.zOffset - camZ)); - for (var iterator = queue.iterator(isTranslucent); iterator.hasNext(); ) { - RenderSection section = iterator.next(); - DrawParameters drawParameters = section.getDrawParameters(terrainRenderType); + drawCount++; + + } + if(drawCount > 0) { + long offset; + int indexCount; + int firstIndex; + int vertexOffset; + for(int i = 0; i < drawCount; ++i) { - MemoryUtil.memPutFloat(ptr + 0, section.xOffset - camX1); - MemoryUtil.memPutFloat(ptr + 4, section.yOffset - camY1); - MemoryUtil.memPutFloat(ptr + 8, section.zOffset - camZ1); + offset = i * 24 + bufferPtr; - nvkCmdPushConstants(commandBuffer, layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 12, ptr); + indexCount = MemoryUtil.memGetInt(offset + 0); + firstIndex = MemoryUtil.memGetInt(offset + 4); + vertexOffset = MemoryUtil.memGetInt(offset + 8); - vkCmdDrawIndexed(commandBuffer, drawParameters.indexCount, 1, drawParameters.firstIndex, drawParameters.vertexOffset, 0); +// if(indexCount == 0) { +// continue; +// } + + nvkCmdPushConstants(commandBuffer, pipeline.getLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 12, offset + 12); + vkCmdDrawIndexed(commandBuffer, indexCount, 1, firstIndex, vertexOffset, 0); + } } + } } diff --git a/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java b/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java index 5d786c5ce..ed51ac6a4 100644 --- a/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java +++ b/src/main/java/net/vulkanmod/render/chunk/WorldRenderer.java @@ -101,7 +101,7 @@ private WorldRenderer(RenderBuffers renderBuffers) { allocateIndirectBuffers(); Renderer.getInstance().addOnResizeCallback(() -> { - if(this.indirectBuffers.length != Vulkan.getSwapChain().getFramesNum()) + if(this.indirectBuffers.length != Renderer.getFramesNum()) allocateIndirectBuffers(); }); } @@ -110,7 +110,7 @@ private void allocateIndirectBuffers() { if(this.indirectBuffers != null) Arrays.stream(this.indirectBuffers).forEach(Buffer::freeBuffer); - this.indirectBuffers = new IndirectBuffer[Vulkan.getSwapChain().getFramesNum()]; + this.indirectBuffers = new IndirectBuffer[Renderer.getFramesNum()]; for(int i = 0; i < this.indirectBuffers.length; ++i) { this.indirectBuffers[i] = new IndirectBuffer(1000000, MemoryTypes.HOST_MEM); diff --git a/src/main/java/net/vulkanmod/vulkan/Renderer.java b/src/main/java/net/vulkanmod/vulkan/Renderer.java index fc4fa47ab..5480687ab 100644 --- a/src/main/java/net/vulkanmod/vulkan/Renderer.java +++ b/src/main/java/net/vulkanmod/vulkan/Renderer.java @@ -3,6 +3,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.client.Minecraft; +import net.vulkanmod.Initializer; import net.vulkanmod.render.chunk.AreaUploadManager; import net.vulkanmod.render.chunk.TerrainShaderManager; import net.vulkanmod.render.profiling.Profiler2; @@ -16,7 +17,6 @@ import net.vulkanmod.vulkan.texture.VTextureSelector; import net.vulkanmod.vulkan.util.VUtil; import org.lwjgl.PointerBuffer; -import org.lwjgl.opengl.GL11C; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.*; @@ -42,9 +42,12 @@ public class Renderer { private static VkDevice device; - private static boolean swapCahinUpdate = false; + private static boolean swapChainUpdate = false; public static boolean skipRendering = false; - public static void initRenderer() { INSTANCE = new Renderer(); } + public static void initRenderer() { + INSTANCE = new Renderer(); + INSTANCE.init(); + } public static Renderer getInstance() { return INSTANCE; } @@ -56,7 +59,7 @@ public class Renderer { private final Set usedPipelines = new ObjectOpenHashSet<>(); - private final Drawer drawer; + private Drawer drawer; private int framesNum; private int imagesNum; @@ -78,17 +81,21 @@ public class Renderer { public Renderer() { device = Vulkan.getDevice(); - - Uniforms.setupDefaultUniforms(); - TerrainShaderManager.init(); - AreaUploadManager.createInstance(); - - framesNum = getSwapChain().getFramesNum(); + framesNum = Initializer.CONFIG.frameQueueSize; imagesNum = getSwapChain().getImagesNum(); + } + + private void init() { + MemoryManager.createInstance(Renderer.getFramesNum()); + Vulkan.createStagingBuffers(); drawer = new Drawer(); drawer.createResources(framesNum); + Uniforms.setupDefaultUniforms(); + TerrainShaderManager.init(); + AreaUploadManager.createInstance(); + allocateCommandBuffers(); createSyncObjects(); @@ -163,9 +170,9 @@ public void beginFrame() { p.pop(); p.push("Frame_fence"); - if(swapCahinUpdate) { + if(swapChainUpdate) { recreateSwapChain(); - swapCahinUpdate = false; + swapChainUpdate = false; if(getSwapChain().getWidth() == 0 && getSwapChain().getHeight() == 0) { skipRendering = true; @@ -210,14 +217,10 @@ public void beginFrame() { imageAvailableSemaphores.get(currentFrame), VK_NULL_HANDLE, pImageIndex); if(vkResult == VK_SUBOPTIMAL_KHR ) { - swapCahinUpdate = true; + swapChainUpdate = true; } - else if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || swapCahinUpdate) { - swapCahinUpdate = true; -// shouldRecreate = false; -// waitForSwapChain(); -// recreateSwapChain(); -// shouldRecreate = true; + else if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || swapChainUpdate) { + swapChainUpdate = true; return; } else if(vkResult != VK_SUCCESS) { throw new RuntimeException("Cannot get image: " + vkResult); @@ -319,7 +322,7 @@ private void resetDescriptors() { } private void submitFrame() { - if(swapCahinUpdate) + if(swapChainUpdate) return; try(MemoryStack stack = stackPush()) { @@ -358,10 +361,8 @@ private void submitFrame() { vkResult = vkQueuePresentKHR(Device.getPresentQueue().queue(), presentInfo); - if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || vkResult == VK_SUBOPTIMAL_KHR || swapCahinUpdate) { - swapCahinUpdate = true; -// shouldRecreate = false; -// recreateSwapChain(); + if(vkResult == VK_ERROR_OUT_OF_DATE_KHR || vkResult == VK_SUBOPTIMAL_KHR || swapChainUpdate) { + swapChainUpdate = true; return; } else if(vkResult != VK_SUCCESS) { throw new RuntimeException("Failed to present swap chain image"); @@ -398,13 +399,15 @@ private void recreateSwapChain() { //Semaphores need to be recreated in order to make them unsignaled destroySyncObjects(); - int newFramesNum = getSwapChain().getFramesNum(); - imagesNum = getSwapChain().getFramesNum(); + int newFramesNum = Initializer.CONFIG.frameQueueSize; + imagesNum = getSwapChain().getImagesNum(); if(framesNum != newFramesNum) { AreaUploadManager.INSTANCE.waitAllUploads(); framesNum = newFramesNum; + MemoryManager.createInstance(newFramesNum); + createStagingBuffers(); allocateCommandBuffers(); Pipeline.recreateDescriptorSets(framesNum); @@ -426,7 +429,6 @@ public void cleanUpResources() { TerrainShaderManager.destroyPipelines(); VTextureSelector.getWhiteTexture().free(); - VTextureSelector.freeAll(); } private void destroySyncObjects() { @@ -622,5 +624,5 @@ public static void popPushDebugSection(String s) { public static VkCommandBuffer getCommandBuffer() { return INSTANCE.currentCmdBuffer; } - public static void scheduleSwapChainUpdate() { swapCahinUpdate = true; } + public static void scheduleSwapChainUpdate() { swapChainUpdate = true; } } diff --git a/src/main/java/net/vulkanmod/vulkan/Vulkan.java b/src/main/java/net/vulkanmod/vulkan/Vulkan.java index 609d66adb..642305ca1 100644 --- a/src/main/java/net/vulkanmod/vulkan/Vulkan.java +++ b/src/main/java/net/vulkanmod/vulkan/Vulkan.java @@ -132,7 +132,6 @@ public static long getAllocator() { private static long allocator; - private static int FramesNum; private static StagingBuffer[] stagingBuffers; public static void initVulkan(long window) { @@ -150,18 +149,16 @@ public static void initVulkan(long window) { allocateImmediateCmdBuffer(); createSwapChain(); - MemoryManager.createInstance(swapChain.getFramesNum()); - - createStagingBuffers(); Renderer.initRenderer(); + } static void createStagingBuffers() { if(stagingBuffers != null) { - Arrays.stream(stagingBuffers).forEach(Buffer::freeBuffer); + freeStagingBuffers(); } - stagingBuffers = new StagingBuffer[getSwapChain().getFramesNum()]; + stagingBuffers = new StagingBuffer[Renderer.getFramesNum()]; for(int i = 0; i < stagingBuffers.length; ++i) { stagingBuffers[i] = new StagingBuffer(30 * 1024 * 1024); @@ -170,19 +167,10 @@ static void createStagingBuffers() { private static void createSwapChain() { swapChain = new SwapChain(); - - FramesNum = swapChain.getFramesNum(); } public static void recreateSwapChain() { - int newFramesNum = swapChain.recreateSwapChain(); - - if (FramesNum != newFramesNum) { - MemoryManager.createInstance(newFramesNum); - createStagingBuffers(); - } - - FramesNum = newFramesNum; + swapChain.recreateSwapChain(); } public static void waitIdle() { @@ -195,13 +183,12 @@ public static void cleanUp() { vkDestroyFence(Device.device, immediateFence, null); Pipeline.destroyPipelineCache(); -// WorldRenderer.getInstance().cleanUp(); + Renderer.getInstance().cleanUpResources(); - swapChain.getRenderPass().cleanUp(); swapChain.cleanUp(); freeStagingBuffers(); -// VTextureSelector.freeAll(); + try { MemoryManager.getInstance().freeAllBuffers(); } catch (Exception e) { @@ -217,9 +204,7 @@ public static void cleanUp() { } private static void freeStagingBuffers() { - for(StagingBuffer buffer : stagingBuffers) { - MemoryManager.freeBuffer(buffer.getId(), buffer.getAllocation()); - } + Arrays.stream(stagingBuffers).forEach(Buffer::freeBuffer); } private static void createInstance() { @@ -236,9 +221,9 @@ private static void createInstance() { appInfo.sType(VK_STRUCTURE_TYPE_APPLICATION_INFO); appInfo.pApplicationName(stack.UTF8Safe("VulkanMod")); - appInfo.applicationVersion(VK_API_VERSION_1_2); - appInfo.pEngineName(stack.UTF8Safe("No Engine")); - appInfo.engineVersion(VK_API_VERSION_1_2); + appInfo.applicationVersion(VK_MAKE_VERSION(1, 0, 0)); + appInfo.pEngineName(stack.UTF8Safe("VulkanMod Engine")); + appInfo.engineVersion(VK_MAKE_VERSION(1, 0, 0)); appInfo.apiVersion(VK_API_VERSION_1_2); VkInstanceCreateInfo createInfo = VkInstanceCreateInfo.calloc(stack); diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java index 7475a55a4..421a000a9 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java @@ -71,7 +71,7 @@ public void addRenderPass(RenderPass renderPass) { public void createImages() { if(this.hasColorAttachment) { this.colorAttachment = VulkanImage.createTextureImage(format, 1, width, height, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, linearFiltering, true); } diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java index 736992984..a2d78e95f 100644 --- a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java +++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java @@ -61,7 +61,7 @@ public SwapChain() { } - public int recreateSwapChain() { + public void recreateSwapChain() { Synchronization.INSTANCE.waitFences(); if(this.depthAttachment != null) { @@ -76,8 +76,6 @@ public int recreateSwapChain() { } createSwapChain(); - - return this.getFramesNum(); } public void createSwapChain() { @@ -101,14 +99,14 @@ public void createSwapChain() { this.height = 0; return; } - //minImageCount depends on driver: Mesa/RADV needs a min of 4, but most other drivers are at least 2 or 3 - int requestedFrames = Math.max(DEFAULT_IMAGE_COUNT, surfaceProperties.capabilities.minImageCount()); + //minImageCount depends on driver: Mesa/RADV needs a min of 4, but most other drivers are at least 2 or 3 + //TODO using FIFO present mode with image num > 2 introduces (unnecessary) input lag + int requestedImages = Math.max(DEFAULT_IMAGE_COUNT, surfaceProperties.capabilities.minImageCount()); - IntBuffer imageCount = stack.ints(requestedFrames); -// IntBuffer imageCount = stack.ints(Math.max(surfaceProperties.capabilities.minImageCount(), preferredImageCount)); + IntBuffer imageCount = stack.ints(requestedImages); - VkSwapchainCreateInfoKHR createInfo = VkSwapchainCreateInfoKHR.callocStack(stack); + VkSwapchainCreateInfoKHR createInfo = VkSwapchainCreateInfoKHR.calloc(stack); createInfo.sType(VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); createInfo.surface(Vulkan.getSurface()); @@ -117,7 +115,7 @@ public void createSwapChain() { this.format = surfaceFormat.format(); this.extent2D = VkExtent2D.create().set(extent); - createInfo.minImageCount(requestedFrames); + createInfo.minImageCount(requestedImages); createInfo.imageFormat(this.format); createInfo.imageColorSpace(surfaceFormat.colorSpace()); createInfo.imageExtent(extent); @@ -161,10 +159,6 @@ public void createSwapChain() { swapChainImages = new ArrayList<>(imageCount.get(0)); - // minImageCount and Actual Image Count can differ with some Drivers, - // According to the spec, minImageCount is only the guaranteed min, not the actual image count - Initializer.LOGGER.info("Requested Images: "+requestedFrames + " -> Actual Image Count: "+imageCount.get(0)); - this.width = extent2D.width(); this.height = extent2D.height(); @@ -302,7 +296,7 @@ public void presentLayout(MemoryStack stack, VkCommandBuffer commandBuffer, int public void cleanUp() { VkDevice device = Vulkan.getDevice(); -// framebuffers.forEach(framebuffer -> vkDestroyFramebuffer(device, framebuffer, null)); + renderPass.cleanUp(); if(!DYNAMIC_RENDERING) { Arrays.stream(framebuffers).forEach(id -> vkDestroyFramebuffer(device, id, null)); @@ -428,7 +422,5 @@ public void setVsync(boolean vsync) { public RenderPass getRenderPass() { return renderPass; } - - public int getFramesNum() { return Initializer.CONFIG.frameQueueSize; } public int getImagesNum() { return this.swapChainImages.size(); } } diff --git a/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java index 523a4ba38..48619fb1b 100644 --- a/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java +++ b/src/main/java/net/vulkanmod/vulkan/memory/AutoIndexBuffer.java @@ -5,8 +5,6 @@ import java.nio.ByteBuffer; import java.nio.ShortBuffer; -import static net.vulkanmod.vulkan.memory.AutoIndexBuffer.DrawType.QUADS; - public class AutoIndexBuffer { int vertexCount; DrawType drawType; @@ -46,7 +44,7 @@ private void createIndexBuffer(int vertexCount) { } public void checkCapacity(int vertexCount) { - if(this.drawType!=QUADS && vertexCount > this.vertexCount) { + if(vertexCount > this.vertexCount) { int newVertexCount = this.vertexCount * 2; System.out.println("Reallocating AutoIndexBuffer from " + this.vertexCount + " to " + newVertexCount); diff --git a/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java b/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java index fb9e65677..49e755324 100644 --- a/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java +++ b/src/main/java/net/vulkanmod/vulkan/memory/UniformBuffers.java @@ -21,7 +21,7 @@ public class UniformBuffers { private List uniformBuffers; private final static int minOffset = (int) Device.deviceProperties.limits().minUniformBufferOffsetAlignment(); - private final int framesSize = getSwapChain().getFramesNum(); + private final int framesSize = Renderer.getFramesNum(); CommandPool.CommandBuffer commandBuffer; diff --git a/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java index ba83c7650..a00906910 100644 --- a/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java +++ b/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java @@ -46,7 +46,7 @@ public class GraphicsPipeline extends Pipeline { graphicsPipelines.computeIfAbsent(new PipelineState(DEFAULT_BLEND_STATE, DEFAULT_DEPTH_STATE, DEFAULT_LOGICOP_STATE, DEFAULT_COLORMASK, builder.renderPass), this::createGraphicsPipeline); - createDescriptorSets(Vulkan.getSwapChain().getFramesNum()); + createDescriptorSets(Renderer.getFramesNum()); PIPELINES.add(this); } diff --git a/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java index 48dd112f2..8160437a5 100644 --- a/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java +++ b/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java @@ -599,7 +599,7 @@ public static int getStageFromString(String s) { return switch (s) { case "vertex" -> VK_SHADER_STAGE_VERTEX_BIT; case "fragment" -> VK_SHADER_STAGE_FRAGMENT_BIT; - case "all" -> VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT; + case "all" -> VK_SHADER_STAGE_ALL_GRAPHICS; case "compute" -> VK_SHADER_STAGE_COMPUTE_BIT; default -> throw new RuntimeException("cannot identify type.."); diff --git a/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java b/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java index 04983c6a3..8e5b1475f 100644 --- a/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java +++ b/src/main/java/net/vulkanmod/vulkan/texture/VTextureSelector.java @@ -87,9 +87,4 @@ public static VulkanImage getOverlayTexture() { public static VulkanImage getWhiteTexture() { return whiteTexture; } - public static void freeAll() - { - framebufferTexture.doFree(); - framebufferTexture2.doFree(); - } } diff --git a/src/main/resources/vulkanmod.mixins.json b/src/main/resources/vulkanmod.mixins.json index 0cbe9fbab..424cdb72c 100644 --- a/src/main/resources/vulkanmod.mixins.json +++ b/src/main/resources/vulkanmod.mixins.json @@ -7,26 +7,32 @@ "mixins": [ ], "client": [ - "InputConstantsM", "WindowMixin", + "chunk.DirectionMixin", "chunk.FrustumMixin", "chunk.LevelRendererMixin", "chunk.VisibilitySetMixin", + "compatibility.EffectInstanceM", "compatibility.ProgramM", "compatibility.UniformM", "compatibility.gl.GL11M", + "debug.ChunkBorderRendererM", "debug.DebugScreenOverlayM", "debug.GlDebugInfoM", "debug.KeyboardHandlerM", + "gui.ChatComponentM", "gui.DebugHudM", "gui.GuiM", + "matrix.Matrix4fM", + "profiling.GuiMixin", "profiling.KeyboardHandlerM", + "render.BufferUploaderM", "render.GameRendererMixin", "render.GlProgramManagerMixin", @@ -47,7 +53,9 @@ "render.vertex.VertexBufferM", "render.vertex.VertexConsumerM", "render.vertex.VertexFormatMixin", + "screen.OptionsScreenM", + "texture.MAbstractTexture", "texture.MDynamicTexture", "texture.MFontTexture", @@ -60,11 +68,16 @@ "texture.MSpriteContents", "texture.MTextureManager", "texture.MTextureUtil", + "util.ScreenshotRecorderM", + "vertex.SpriteCoordinateExpanderM", "vertex.VertexMultiConsumersM$DoubleM", "vertex.VertexMultiConsumersM$MultipleM", - "vertex.VertexMultiConsumersM$SheetDecalM" + "vertex.VertexMultiConsumersM$SheetDecalM", + + "wayland.InputConstantsM", + "wayland.MinecraftMixin" ], "injectors": { "defaultRequire": 1