From f189b33e42b9f3697e0607e063f3daee9d51c110 Mon Sep 17 00:00:00 2001 From: Cheng Cao Date: Sat, 7 Oct 2023 16:12:24 -0700 Subject: [PATCH] Makes it not crash and runs normal shaders properly 1. Handles null raytracing shaders list (make it possible to add vk compute and fragment stuff later) 2. Adds support for all the GL image formats listed and used by Optifine 3. Handles destruction and stuff... Ideally this should be handled by a render graph later down the line --- .../client/rendering/VulkanPipeline.java | 11 +++- .../vulkanite/lib/memory/VmaAllocator.java | 59 +++++++++++++++++++ .../vulkanite/lib/other/FormatConverter.java | 32 +++++++++- .../iris/MixinNewWorldRenderingPipeline.java | 12 ++-- 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java b/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java index e58708d..1d44e93 100644 --- a/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java +++ b/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java @@ -40,6 +40,7 @@ import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.*; +import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.util.*; @@ -61,7 +62,7 @@ public class VulkanPipeline { private final VCommandPool singleUsePool; private record RtPipeline(VRaytracePipeline pipeline, int commonSet, int geomSet, int customTexSet, int ssboSet) {} - private RtPipeline[] raytracePipelines; + private ArrayList raytracePipelines = new ArrayList<>(); private final VSampler sampler; private final VSampler ctexSampler; @@ -162,6 +163,10 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray .borderColor(VK_BORDER_COLOR_INT_OPAQUE_BLACK) .maxAnisotropy(1.0f)); + if (passes == null) { + return; + } + try { var commonSetExpected = new ShaderReflection.Set(new ShaderReflection.Binding[]{ new ShaderReflection.Binding("", 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, false), @@ -188,7 +193,6 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray } var ssboSetExpected = new ShaderReflection.Set(ssboBindings); - raytracePipelines = new RtPipeline[passes.length]; for (int i = 0; i < passes.length; i++) { var builder = new RaytracePipelineBuilder(); passes[i].apply(builder); @@ -215,7 +219,7 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray } } - raytracePipelines[i] = new RtPipeline(pipe, commonSet, geomSet, customTexSet, ssboSet); + raytracePipelines.add(new RtPipeline(pipe, commonSet, geomSet, customTexSet, ssboSet)); } } catch (Exception e) { @@ -244,6 +248,7 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag var tlasLink = ctx.sync.createBinarySemaphore(); var tlas = accelerationManager.buildTLAS(in, tlasLink); + if (tlas == null) { glFinish(); tlasLink.free(); diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VmaAllocator.java b/src/main/java/me/cortex/vulkanite/lib/memory/VmaAllocator.java index 4853867..4c5a424 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VmaAllocator.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VmaAllocator.java @@ -10,6 +10,7 @@ import java.nio.IntBuffer; import java.nio.LongBuffer; +import java.util.HashMap; import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static org.lwjgl.system.MemoryStack.stackPush; @@ -29,6 +30,62 @@ public class VmaAllocator { private final VkExportMemoryAllocateInfo exportMemoryAllocateInfo; + private record ImageFormatQuery(int format, int imageType, int tiling, int usage, int flags) {} + private record ImageFormatQueryResult(boolean supported, ImageFormatQuery updatedParams) {} + private HashMap formatSupportCache = new HashMap<>(); + + boolean testModifyFormatSupport(VkDevice device, VkImageCreateInfo imageCreateInfo) { + var query = new ImageFormatQuery(imageCreateInfo.format(), imageCreateInfo.imageType(), imageCreateInfo.tiling(), + imageCreateInfo.usage(), imageCreateInfo.flags()); + if (formatSupportCache.containsKey(query)) { + var res = formatSupportCache.get(query); + if (res.supported) { + imageCreateInfo.format(res.updatedParams.format); + imageCreateInfo.imageType(res.updatedParams.imageType); + imageCreateInfo.tiling(res.updatedParams.tiling); + imageCreateInfo.usage(res.updatedParams.usage); + imageCreateInfo.flags(res.updatedParams.flags); + } + return res.supported; + } + + try (var stack = stackPush()) { + var pImageFormatProperties = VkImageFormatProperties.callocStack(stack); + var result = vkGetPhysicalDeviceImageFormatProperties(device.getPhysicalDevice(), imageCreateInfo.format(), + imageCreateInfo.imageType(), imageCreateInfo.tiling(), imageCreateInfo.usage(), + imageCreateInfo.flags(), pImageFormatProperties); + if (result == VK_SUCCESS) { + formatSupportCache.put(query, new ImageFormatQueryResult(true, query)); + return true; + } else if (result != VK_ERROR_FORMAT_NOT_SUPPORTED) { + throw new RuntimeException("Failed to get image format properties"); + } + + // If storage image is set, try to un-set it + if ((imageCreateInfo.usage() & VK_IMAGE_USAGE_STORAGE_BIT) != 0) { + imageCreateInfo.usage(imageCreateInfo.usage() & ~VK_IMAGE_USAGE_STORAGE_BIT); + boolean res = testModifyFormatSupport(device, imageCreateInfo); + if (res) { + System.err.println("WARNING: Storage image usage was removed from " + imageCreateInfo.format() + " due to lack of support"); + } + return res; + } + + // If tiling is optimal, try linear + if (imageCreateInfo.tiling() == VK_IMAGE_TILING_OPTIMAL) { + imageCreateInfo.tiling(VK_IMAGE_TILING_LINEAR); + boolean res = testModifyFormatSupport(device, imageCreateInfo); + if (res) { + System.err.println("WARNING: TILING_OPTIMAL was changed to TILING_LINEAR " + imageCreateInfo.format() + " due to lack of support"); + } + return res; + } + } + + formatSupportCache.put(query, new ImageFormatQueryResult(false, null)); + return false; + } + public VmaAllocator(VkDevice device, boolean enableDeviceAddresses, long sharedBlockSize, int sharedHandleType) { this.device = device; this.hasDeviceAddresses = enableDeviceAddresses; @@ -172,6 +229,7 @@ BufferAllocation alloc(long pool, VkBufferCreateInfo bufferCreateInfo, VmaAlloca } SharedImageAllocation allocShared(VkImageCreateInfo imageCreateInfo, VmaAllocationCreateInfo allocationCreateInfo) { + testModifyFormatSupport(device, imageCreateInfo); try (var stack = stackPush()) { LongBuffer pb = stack.callocLong(1); _CHECK_(vkCreateImage(device, imageCreateInfo, null, pb), "Failed to create VkBuffer"); @@ -197,6 +255,7 @@ SharedImageAllocation allocShared(VkImageCreateInfo imageCreateInfo, VmaAllocati } ImageAllocation alloc(long pool, VkImageCreateInfo imageCreateInfo, VmaAllocationCreateInfo allocationCreateInfo) { + testModifyFormatSupport(device, imageCreateInfo); try (var stack = stackPush()) { LongBuffer pi = stack.mallocLong(1); PointerBuffer pa = stack.mallocPointer(1); diff --git a/src/main/java/me/cortex/vulkanite/lib/other/FormatConverter.java b/src/main/java/me/cortex/vulkanite/lib/other/FormatConverter.java index efafa57..ee0e778 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/FormatConverter.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/FormatConverter.java @@ -14,15 +14,45 @@ public static int getVkFormatFromGl(InternalTextureFormat format) { // TODO: Support 3 component types return switch (format.getGlFormat()) { + // Weird formats case GL_R11F_G11F_B10F -> VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case GL_RGB10_A2, GL_RGB10 -> VK_FORMAT_A2B10G10R10_UNORM_PACK32; + case GL_RGB5, GL_RGB5_A1 -> VK_FORMAT_A1R5G5B5_UNORM_PACK16; + case GL_RGB9_E5 -> VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; - + // Floats case GL_RGB32F, GL_RGBA32F -> VK_FORMAT_R32G32B32A32_SFLOAT; case GL_RGB16F, GL_RGBA16F -> VK_FORMAT_R16G16B16A16_SFLOAT; + case GL_RG16F -> VK_FORMAT_R16G16_SFLOAT; case GL_R16F -> VK_FORMAT_R16_SFLOAT; + // Unorms case GL_RGB16, GL_RGBA16 -> VK_FORMAT_R16G16B16A16_UNORM; + case GL_RG16 -> VK_FORMAT_R16G16_UNORM; + case GL_R16 -> VK_FORMAT_R16_UNORM; case GL_RGBA, GL_RGB8, GL_RGBA8 -> VK_FORMAT_R8G8B8A8_UNORM; + case GL_RG8 -> VK_FORMAT_R8G8_UNORM; + case GL_R8 -> VK_FORMAT_R8_UNORM; + + // Ints + case GL_RGB32I, GL_RGBA32I -> VK_FORMAT_R32G32B32A32_SINT; + case GL_RG32I -> VK_FORMAT_R32G32_SINT; + case GL_R32I -> VK_FORMAT_R32_SINT; + case GL_RGB32UI, GL_RGBA32UI -> VK_FORMAT_R32G32B32A32_UINT; + case GL_RG32UI -> VK_FORMAT_R32G32_UINT; + case GL_R32UI -> VK_FORMAT_R32_UINT; + case GL_RGB16I, GL_RGBA16I -> VK_FORMAT_R16G16B16A16_SINT; + case GL_RG16I -> VK_FORMAT_R16G16_SINT; + case GL_R16I -> VK_FORMAT_R16_SINT; + case GL_RGB16UI, GL_RGBA16UI -> VK_FORMAT_R16G16B16A16_UINT; + case GL_RG16UI -> VK_FORMAT_R16G16_UINT; + case GL_R16UI -> VK_FORMAT_R16_UINT; + case GL_RGB8I, GL_RGBA8I -> VK_FORMAT_R8G8B8A8_SINT; + case GL_RG8I -> VK_FORMAT_R8G8_SINT; + case GL_R8I -> VK_FORMAT_R8_SINT; + case GL_RGB8UI, GL_RGBA8UI -> VK_FORMAT_R8G8B8A8_UINT; + case GL_RG8UI -> VK_FORMAT_R8G8_UINT; + case GL_R8UI -> VK_FORMAT_R8_UINT; default -> { throw new IllegalArgumentException("No known conversion to VK type for GL type " + format + " (" + format.getGlFormat() + ")."); diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java index 341253b..6f2fcd2 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java @@ -71,9 +71,9 @@ private void injectRTShader(ProgramSet set, CallbackInfo ci) { for (int i = 0; i < passes.length; i++) { rtShaderPasses[i] = new RaytracingShaderSet(ctx, passes[i]); } - - pipeline = new VulkanPipeline(ctx, Vulkanite.INSTANCE.getAccelerationManager(), rtShaderPasses, set.getPackDirectives().getBufferObjects().keySet().toArray(new int[0]), getCustomTextures()); } + // Still create this, later down the line we might add Vulkan compute pipelines or mesh shading, etc. + pipeline = new VulkanPipeline(ctx, Vulkanite.INSTANCE.getAccelerationManager(), rtShaderPasses, set.getPackDirectives().getBufferObjects().keySet().toArray(new int[0]), getCustomTextures()); } @Inject(method = "renderShadows", at = @At("TAIL")) @@ -93,14 +93,14 @@ private void renderShadows(LevelRendererAccessor par1, Camera par2, CallbackInfo @Inject(method = "destroyShaders", at = @At("TAIL")) private void destory(CallbackInfo ci) { + ctx.cmd.waitQueueIdle(0); if (rtShaderPasses != null) { - ctx.cmd.waitQueueIdle(0); for (var pass : rtShaderPasses) { pass.delete(); } - pipeline.destory(); - rtShaderPasses = null; - pipeline = null; } + pipeline.destory(); + rtShaderPasses = null; + pipeline = null; } }