diff --git a/README.md b/README.md index 19b7410..9d1a36c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # Work in progress Minecraft mod that adds hardware raytracing support to minecraft using opengl vulkan interop -Enables extra passes that shader devs can use with raytracing passes \ No newline at end of file +Enables extra passes that shader devs can use with raytracing passes diff --git a/build.gradle b/build.gradle index 1a6d7e4..bd98c4b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' } @@ -38,8 +38,8 @@ dependencies { modImplementation("net.fabricmc.fabric-api:fabric-rendering-data-attachment-v1:0.3.38+73761d2e9a") modImplementation(fabricApi.module("fabric-resource-loader-v0", project.fabric_version)) - modImplementation "maven.modrinth:sodium:mc1.20.2-0.5.3" - modImplementation "maven.modrinth:iris:1.6.9+1.20.2" + modImplementation "maven.modrinth:sodium:mc1.20.6-0.5.8" + modImplementation "maven.modrinth:iris:1.7.0+1.20.6" modRuntimeOnly 'org.anarres:jcpp:1.4.14' modRuntimeOnly 'io.github.douira:glsl-transformer:2.0.0-pre13' @@ -106,7 +106,8 @@ publishing { import org.gradle.internal.os.OperatingSystem -project.ext.lwjglVersion = "3.3.1" +project.ext.lwjglVersion = "3.3.3" +project.ext.jomlVersion = "1.10.4" switch (OperatingSystem.current()) { case OperatingSystem.LINUX: @@ -123,14 +124,14 @@ switch (OperatingSystem.current()) { repositories { mavenCentral() } -project.ext.lwjglNatives = "natives-windows" dependencies { + include(implementation("org.joml:joml:${jomlVersion}")) + implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion") include(implementation("org.lwjgl:lwjgl-meshoptimizer")) include(implementation("org.lwjgl:lwjgl-vma")) - include(implementation("org.lwjgl:lwjgl-vulkan")) include(implementation("org.lwjgl:lwjgl-shaderc")) include(implementation("org.lwjgl:lwjgl-spvc")) @@ -139,12 +140,12 @@ dependencies { include(runtimeOnly("org.lwjgl:lwjgl-shaderc:$lwjglVersion:$lwjglNatives")) include(runtimeOnly("org.lwjgl:lwjgl-spvc:$lwjglVersion:$lwjglNatives")) + include(implementation("org.lwjgl:lwjgl-vulkan:$lwjglVersion")) include(implementation("org.lwjgl:lwjgl-meshoptimizer:$lwjglVersion:$lwjglNatives")) include(implementation("org.lwjgl:lwjgl-vma:$lwjglVersion:$lwjglNatives")) include(implementation("org.lwjgl:lwjgl-shaderc:$lwjglVersion:$lwjglNatives")) include(implementation("org.lwjgl:lwjgl-spvc:$lwjglVersion:$lwjglNatives")) - implementation "org.lwjgl:lwjgl" implementation "org.lwjgl:lwjgl-glfw" implementation "org.lwjgl:lwjgl-opengl" @@ -152,34 +153,3 @@ dependencies { runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" } - - -project.ext.lwjglVersion = "3.3.1" -project.ext.jomlVersion = "1.10.4" -project.ext.winNatives = "natives-windows" -project.ext.linuxNatives = "natives-linux" - -dependencies { - include(implementation("org.lwjgl:lwjgl:$lwjglVersion")) - include(implementation("org.lwjgl:lwjgl-vulkan:$lwjglVersion")) - include(implementation("org.lwjgl:lwjgl-vma:$lwjglVersion")) - include(implementation("org.joml:joml:${jomlVersion}")) - include(runtimeOnly("org.lwjgl:lwjgl-vma:$lwjglVersion:$winNatives")) - include(runtimeOnly("org.lwjgl:lwjgl-vma:$lwjglVersion:$linuxNatives")) - - include(implementation("org.lwjgl:lwjgl-glfw:$lwjglVersion")) - include(runtimeOnly("org.lwjgl:lwjgl-glfw:$lwjglVersion:$winNatives")) - include(runtimeOnly("org.lwjgl:lwjgl-glfw:$lwjglVersion:$linuxNatives")) - include(implementation("org.lwjgl:lwjgl-stb:$lwjglVersion")) - include(runtimeOnly("org.lwjgl:lwjgl-stb:$lwjglVersion:$winNatives")) - include(runtimeOnly("org.lwjgl:lwjgl-stb:$lwjglVersion:$linuxNatives")) - include(implementation("org.lwjgl:lwjgl-openal:$lwjglVersion")) - include(runtimeOnly("org.lwjgl:lwjgl-openal:$lwjglVersion:$winNatives")) - include(runtimeOnly("org.lwjgl:lwjgl-openal:$lwjglVersion:$linuxNatives")) - include(runtimeOnly("org.lwjgl:lwjgl:$lwjglVersion:$winNatives")) - include(runtimeOnly("org.lwjgl:lwjgl:$lwjglVersion:$linuxNatives")) - - include(implementation("org.lwjgl:lwjgl-shaderc:$lwjglVersion")) - include(runtimeOnly("org.lwjgl:lwjgl-shaderc:$lwjglVersion:$winNatives")) - include(runtimeOnly("org.lwjgl:lwjgl-shaderc:$lwjglVersion:$linuxNatives")) -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index b0b4fc5..72a8854 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,12 +2,12 @@ org.gradle.jvmargs=-Xmx4G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.20.2 -yarn_mappings=1.20.2+build.1 -loader_version=0.14.21 +minecraft_version=1.20.6 +yarn_mappings=1.20.6+build.3 +loader_version=0.15.11 #Fabric api -fabric_version=0.88.5+1.20.2 +fabric_version=0.99.4+1.20.6 # Mod Properties mod_version=0.0.4-pre-alpha maven_group=me.cortex diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c85a1f..20db9ad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/me/cortex/vulkanite/acceleration/AccelerationBlasBuilder.java b/src/main/java/me/cortex/vulkanite/acceleration/AccelerationBlasBuilder.java index be979c7..13540af 100644 --- a/src/main/java/me/cortex/vulkanite/acceleration/AccelerationBlasBuilder.java +++ b/src/main/java/me/cortex/vulkanite/acceleration/AccelerationBlasBuilder.java @@ -7,10 +7,14 @@ import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IAccelerationBuildResult; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; +import me.cortex.vulkanite.lib.base.VRegistry; import me.cortex.vulkanite.lib.cmd.VCmdBuff; import me.cortex.vulkanite.lib.cmd.VCommandPool; import me.cortex.vulkanite.lib.descriptors.DescriptorSetLayoutBuilder; import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; +import me.cortex.vulkanite.lib.memory.AccelerationStructurePool; +import me.cortex.vulkanite.lib.memory.PoolLinearAllocator; import me.cortex.vulkanite.lib.memory.VAccelerationStructure; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.other.VQueryPool; @@ -45,27 +49,32 @@ public class AccelerationBlasBuilder { private final VContext context; private record BLASTriangleData(int quadCount, int geometryFlags) {} private record BLASBuildJob(List geometries, JobPassThroughData data) {} - public record BLASBuildResult(VAccelerationStructure structure, JobPassThroughData data) {} - public record BLASBatchResult(List results, VSemaphore semaphore) { } - private final Thread worker; + public record BLASBuildResult(VRef structure, JobPassThroughData data) {} + public record BLASBatchResult(List results, long execution) { } + private final int asyncQueue; private final Consumer resultConsumer; - private final VCommandPool sinlgeUsePool; - private final VQueryPool queryPool; + private final VRef queryPool; //TODO: maybe move to an executor type system private final Semaphore awaitingJobBatchess = new Semaphore(0);//Note: this is done to avoid spin locking on the job consumer private final ConcurrentLinkedDeque> batchedJobs = new ConcurrentLinkedDeque<>(); - private final VComputePipeline gpuVertexDecodePipeline; + private final VRef gpuVertexDecodePipeline; + + public int getAsyncQueue() { + return asyncQueue; + } + + private final AccelerationStructurePool accelerationStructurePool; public AccelerationBlasBuilder(VContext context, int asyncQueue, Consumer resultConsumer) { - this.sinlgeUsePool = context.cmd.createSingleUsePool(); - this.queryPool = new VQueryPool(context.device, 10000, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR); + this.queryPool = VQueryPool.create(context.device, 10000, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR); this.context = context; this.asyncQueue = asyncQueue; this.resultConsumer = resultConsumer; + this.accelerationStructurePool = new AccelerationStructurePool(context); var decodeShader = VShader.compileLoad(context, """ #version 460 @@ -99,7 +108,7 @@ public AccelerationBlasBuilder(VContext context, int asyncQueue, Consumer jobs = new ArrayList<>(); + Deque priorExecutions = new ArrayDeque<>(3); while (true) { { jobs.clear(); @@ -146,7 +162,7 @@ private void run() { } int i = -1; //Collect the job batch - while (!this.batchedJobs.isEmpty()) { + while (!this.batchedJobs.isEmpty() && jobs.size() < 32) { i++; jobs.addAll(this.batchedJobs.poll()); } @@ -159,11 +175,11 @@ private void run() { } } } - sinlgeUsePool.doReleases(); - if (jobs.size() > 100) { - System.err.println("EXCESSIVE JOBS FOR SOME REASON AAAAAAAAAA"); - //while (true); - } + + VRegistry.INSTANCE.threadLocalCollect(); + + var sinlgeUsePoolWorker = context.cmd.getSingleUsePool(); + //Jobs are batched and built on the async vulkan queue then block synchronized with fence // which then results in compaction and dispatch to consumer @@ -173,15 +189,15 @@ private void run() { PointerBuffer buildRanges = stack.mallocPointer(jobs.size()); LongBuffer pAccelerationStructures = stack.mallocLong(jobs.size()); - List buffersToFree = new ArrayList<>(jobs.size() * 2); - var scratchBuffers = new VBuffer[jobs.size()]; - var accelerationStructures = new VAccelerationStructure[jobs.size()]; + var accelerationStructures = new ArrayList>(jobs.size()); - var uploadBuildCmd = sinlgeUsePool.createCommandBuffer(); - uploadBuildCmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + var uploadBuildCmdRef = sinlgeUsePoolWorker.createCommandBuffer(); + var uploadBuildCmd = uploadBuildCmdRef.get(); //Fill in the buildInfo and buildRanges int i = -1; + uploadBuildCmd.bindCompute(gpuVertexDecodePipeline); + for (var job : jobs) { i++; var brs = VkAccelerationStructureBuildRangeInfoKHR.calloc(job.geometries.size(), stack); @@ -189,26 +205,7 @@ private void run() { var maxPrims = stack.callocInt(job.geometries.size()); buildRanges.put(brs); - long buildBufferSize = 0; - - int vertexStride = 4 * 3; - for (var geometry : job.geometries) { - buildBufferSize += geometry.quadCount * 4 * vertexStride; - } - - if (buildBufferSize <= 0) { - throw new IllegalStateException("Build buffer size <= 0"); - } - - var buildBuffer = context.memory.createBuffer(buildBufferSize, - VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR - | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - 0, 0); - buffersToFree.add(buildBuffer); - var buildBufferAddr = buildBuffer.deviceAddress(); - long buildBufferOffset = 0; + long vertexStride = 4 * 3; for (int geoIdx = 0; geoIdx < job.geometries.size(); geoIdx++) { var geometry = job.geometries.get(geoIdx); @@ -216,25 +213,46 @@ private void run() { var geometryInfo = geometryInfos.get().sType$Default(); var br = brs.get(); + long buildBufferSize = geometry.quadCount * 4L * vertexStride; + var buildBuffer = buildBufferAllocator.allocate(buildBufferSize); + + uploadBuildCmd.encodeBufferBarrier(buildBuffer.buffer(), buildBuffer.offset(), buildBuffer.size(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + // We know the geometry data has been uploaded // 0: n_vertices // 1: inAddr // 2: outAddr var pushConstant = new long[3]; - pushConstant[0] = geometry.quadCount * 4; - pushConstant[1] = job.data.geometryBuffers().get(geoIdx).deviceAddress(); - pushConstant[2] = buildBufferAddr + buildBufferOffset; - vkCmdBindPipeline(uploadBuildCmd.buffer, VK_PIPELINE_BIND_POINT_COMPUTE, gpuVertexDecodePipeline.pipeline()); - vkCmdPushConstants(uploadBuildCmd.buffer, gpuVertexDecodePipeline.layout(), VK_SHADER_STAGE_ALL, 0, pushConstant); - vkCmdDispatch(uploadBuildCmd.buffer, Math.min((geometry.quadCount * 4 + 255) / 256, 128), 1, 1); - - VkDeviceOrHostAddressConstKHR indexData = SharedQuadVkIndexBuffer.getIndexBuffer(context, + var geometryInputBuffer = job.data.geometryBuffer(); + var geometryInputBufferOffset = job.data.bufferOffsets().get(geoIdx); + pushConstant[0] = geometry.quadCount * 4L; + pushConstant[1] = geometryInputBuffer.get().deviceAddress() + geometryInputBufferOffset; + pushConstant[2] = buildBuffer.deviceAddress(); + if (pushConstant[1] == 0) { + throw new IllegalStateException("Geometry input buffer address is 0"); + } + if (pushConstant[2] == 0) { + throw new IllegalStateException("Build buffer address is 0"); + } + uploadBuildCmd.pushConstants(0, pushConstant); + uploadBuildCmd.encodeBufferBarrier(geometryInputBuffer, 0, VK_WHOLE_SIZE, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + uploadBuildCmd.dispatch(Math.min((geometry.quadCount * 4 + 255) / 256, 256), 1, 1); + + uploadBuildCmd.encodeBufferBarrier(buildBuffer.buffer(), buildBuffer.offset(), buildBuffer.size(), VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + + var indexBuffer = SharedQuadVkIndexBuffer.getIndexBuffer(context, uploadBuildCmd, Integer.max(geometry.quadCount, 30000)); + VkDeviceOrHostAddressConstKHR indexData = indexBuffer.get().deviceAddressConst(); int indexType = SharedQuadVkIndexBuffer.TYPE; + uploadBuildCmd.addBufferRef(indexBuffer); + VkDeviceOrHostAddressConstKHR vertexData = VkDeviceOrHostAddressConstKHR.calloc(stack) - .deviceAddress(buildBufferAddr + buildBufferOffset); + .deviceAddress(buildBuffer.deviceAddress()); int vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; geometryInfo.geometry(VkAccelerationStructureGeometryDataKHR.calloc(stack) @@ -255,12 +273,8 @@ private void run() { br.primitiveCount(geometry.quadCount * 2); //maxPrims.put(2); //br.primitiveCount(2); - - buildBufferOffset += geometry.quadCount * 4 * vertexStride; } - uploadBuildCmd.encodeBufferBarrier(buildBuffer, 0, VK_WHOLE_SIZE, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); geometryInfos.rewind(); maxPrims.rewind(); @@ -284,154 +298,95 @@ private void run() { buildSizesInfo); - var structure = context.memory.createAcceleration(buildSizesInfo.accelerationStructureSize(), 256, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); - - var scratch = context.memory.createBuffer(buildSizesInfo.buildScratchSize(), - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 256, 0); + var backingBuffer = initialASBufferAllocator.allocate(buildSizesInfo.accelerationStructureSize()); + var structure = context.memory.createAcceleration(backingBuffer.buffer(), backingBuffer.offset(), backingBuffer.size(), VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); + var scratch = scratchAllocator.allocate(buildSizesInfo.buildScratchSize()); + uploadBuildCmd.addBufferRef(scratch.buffer()); bi.scratchData(VkDeviceOrHostAddressKHR.calloc(stack).deviceAddress(scratch.deviceAddress())); - bi.dstAccelerationStructure(structure.structure); + bi.dstAccelerationStructure(structure.get().structure); - pAccelerationStructures.put(structure.structure); + pAccelerationStructures.put(structure.get().structure); - accelerationStructures[i] = structure; - scratchBuffers[i] = scratch; + accelerationStructures.add(structure); } buildInfos.rewind(); buildRanges.rewind(); pAccelerationStructures.rewind(); - VSemaphore link = context.sync.createBinarySemaphore(); { - vkCmdBuildAccelerationStructuresKHR(uploadBuildCmd.buffer, buildInfos, buildRanges); + vkCmdBuildAccelerationStructuresKHR(uploadBuildCmd.buffer(), buildInfos, buildRanges); //TODO: should probably do memory barrier to read access uploadBuildCmd.encodeMemoryBarrier(); - queryPool.reset(uploadBuildCmd, 0, jobs.size()); + uploadBuildCmd.resetQueryPool(queryPool, 0, jobs.size()); vkCmdWriteAccelerationStructuresPropertiesKHR( - uploadBuildCmd.buffer, + uploadBuildCmd.buffer(), pAccelerationStructures, VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, - queryPool.pool, + queryPool.get().pool, 0); - uploadBuildCmd.end(); + long buildExecution = context.cmd.submit(asyncQueue, uploadBuildCmdRef); - VFence buildFence = context.sync.createFence(); - context.cmd.submit(asyncQueue, new VCmdBuff[]{uploadBuildCmd}, new VSemaphore[0], new int[0], - new VSemaphore[]{link}, - buildFence); - - //vkDeviceWaitIdle(context.device); - { - //We need to wait for the fence which signals that the build has finished and we can query the result - // TODO: find a cleaner way to wait on the query results (tho i think waiting on a fence is realistically the easiest thing to do) - vkWaitForFences(context.device, buildFence.address(), true, -1); - - //FIXME: this is extream jank, we can clean up after this point because we know the fence has passed, this is so ugly tho - - for (var sb : scratchBuffers) { - sb.free(); - } - for (var b : buffersToFree) { - b.free(); - } - - sinlgeUsePool.releaseNow(uploadBuildCmd); - - //We can destroy the fence here since we know its passed - buildFence.free(); - } + // Waiting on a semaphore is realistically the easiest thing to do rn + context.cmd.hostWaitForExecution(asyncQueue, buildExecution); + uploadBuildCmdRef.close(); } - long[] compactedSizes = queryPool.getResultsLong(jobs.size()); - VSemaphore awaitSemaphore = context.sync.createBinarySemaphore(); - - VAccelerationStructure[] compactedAS = new VAccelerationStructure[jobs.size()]; + long[] compactedSizes = queryPool.get().getResultsLong(jobs.size()); List results = new ArrayList<>(); //vkDeviceWaitIdle(context.device); //--------------------- + long blasExecution = 0; { - var cmd = sinlgeUsePool.createCommandBuffer(); - cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - - //Dont need a memory barrier cause submit ensures cache flushing already + var cmdRef = sinlgeUsePoolWorker.createCommandBuffer(); + // Dont need a memory barrier cause submit ensures cache flushing already for (int idx = 0; idx < compactedSizes.length; idx++) { - var as = context.memory.createAcceleration(compactedSizes[idx], 256, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); + var compact_as = accelerationStructurePool.createAcceleration(compactedSizes[idx], VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); + var fat_as = accelerationStructures.get(idx); - vkCmdCopyAccelerationStructureKHR(cmd.buffer, VkCopyAccelerationStructureInfoKHR.calloc(stack).sType$Default() - .src(accelerationStructures[idx].structure) - .dst(as.structure) + vkCmdCopyAccelerationStructureKHR(cmdRef.get().buffer(), VkCopyAccelerationStructureInfoKHR.calloc(stack).sType$Default() + .src(fat_as.get().structure) + .dst(compact_as.get().structure) .mode(VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR)); - compactedAS[idx] = as; + cmdRef.get().addAccelerationStructureRef(fat_as); + cmdRef.get().addAccelerationStructureRef(compact_as); + fat_as.close(); + var job = jobs.get(idx); - results.add(new BLASBuildResult(as, job.data)); + results.add(new BLASBuildResult(compact_as, job.data)); } - vkCmdPipelineBarrier(cmd.buffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, null, null, null); - - VFence fence = context.sync.createFence(); - - cmd.end(); - context.cmd.submit(asyncQueue, new VCmdBuff[]{cmd}, - new VSemaphore[]{link}, - new int[]{VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR}, - new VSemaphore[]{awaitSemaphore}, - fence); - - context.sync.addCallback(fence, () -> { - for (var as : accelerationStructures) { - as.free(); - } - - sinlgeUsePool.releaseNow(cmd); - fence.free(); - link.free(); - }); + blasExecution = context.cmd.submit(asyncQueue, cmdRef); + cmdRef.close(); } - //Submit to callback, linking the build semaphore so that we dont stall the queue more than we need - resultConsumer.accept(new BLASBatchResult(results, awaitSemaphore)); + accelerationStructures.forEach(VRef::close); - //TODO: FIXME, so there is an issue in that the query pool needs to be represented per thing - // since the cpu can run ahead of the gpu, need multiple query pools until we know the gpu is finished with it - // using a fence, OR FOR THREAD ONLY we can assume that we allow one batch per queue - //that is, at the end (here) we do a vkWaitForFences on the final fence, _then_ we can release all the temporary - // resources that we know weve used, TODO: I THINK I FIXED THIS BY PUTTING A FENCE SYNC between stage 1 and 2 + resultConsumer.accept(new BLASBatchResult(results, blasExecution)); - //NOTE: THIS IS ACTUALLY WRONG, since we need to block on the query result in order to do the second part - // it doesnt matter about needing multiple query pools - - //vkDeviceWaitIdle(context.device); + priorExecutions.add(blasExecution); + if (priorExecutions.size() > 3) { + long prior = priorExecutions.poll(); + context.cmd.hostWaitForExecution(asyncQueue, prior); + } } } } - - private VBuffer uploadTerrainGeometry(BuiltSectionMeshParts meshParts, VCmdBuff cmd) { - var buff = context.memory.createBuffer(meshParts.getVertexData().getLength(), - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - cmd.encodeDataUpload(context.memory, MemoryUtil.memAddress(meshParts.getVertexData().getDirectBuffer()), buff, 0, meshParts.getVertexData().getLength()); - - return buff; - } - - //Enqueues jobs of section blas builds + // Enqueues jobs of section blas builds + // NOTE: This is on a different thread! public void enqueue(List batch) { - var cmd = sinlgeUsePool.createCommandBuffer(); + var cmd = context.cmd.getSingleUsePool().createCommandBuffer(); boolean hasJobs = false; List jobs = new ArrayList<>(batch.size()); @@ -439,38 +394,61 @@ public void enqueue(List batch) { var acbr = ((IAccelerationBuildResult) cbr).getAccelerationGeometryData(); if (acbr == null) continue; - List buildData = new ArrayList<>(); - List geometryBuffers = new ArrayList<>(); - for (var entry : acbr.entrySet()) { - int flag = entry.getKey() == DefaultTerrainRenderPasses.SOLID ? VK_GEOMETRY_OPAQUE_BIT_KHR : 0; - buildData.add(new BLASTriangleData(entry.getValue().quadCount(), flag)); + List geometries = new ArrayList<>(); + + long totalSize = 0; + for (var entry : acbr.entrySet()) { var geometry = cbr.getMesh(entry.getKey()); - if (geometry.getVertexData().getLength() == 0) { + var dataSize = geometry.getVertexData().getLength(); + if (dataSize == 0) { throw new IllegalStateException(); } - if (!hasJobs) { hasJobs = true; - cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); } + totalSize += dataSize; + geometries.add(geometry); + } + + var geomBuffer = context.memory.createBuffer(totalSize, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + geomBuffer.get().setDebugUtilsObjectName("Terrain geometry buffer"); + + List buildData = new ArrayList<>(); + List bufferOffsets = new ArrayList<>(); + int i = 0; + long destOffset = 0; + for (var entry : acbr.entrySet()) { + int flag = entry.getKey() == DefaultTerrainRenderPasses.SOLID ? VK_GEOMETRY_OPAQUE_BIT_KHR : 0; + buildData.add(new BLASTriangleData(entry.getValue().quadCount(), flag)); + + var meshParts = geometries.get(i); + long dataSize = meshParts.getVertexData().getLength(); + + cmd.get().encodeDataUpload(context.memory, MemoryUtil.memAddress(meshParts.getVertexData().getDirectBuffer()), geomBuffer, destOffset, dataSize); + bufferOffsets.add(destOffset); - geometryBuffers.add(uploadTerrainGeometry(geometry, cmd)); + destOffset += dataSize; + i++; } - if (buildData.size() > 0) { + if (!buildData.isEmpty()) { jobs.add(new BLASBuildJob(buildData, - new JobPassThroughData(cbr.render, cbr.buildTime, geometryBuffers))); + new JobPassThroughData(cbr.render, cbr.buildTime, geomBuffer, bufferOffsets))); } } if (hasJobs) { - cmd.end(); - context.cmd.submitOnceAndWait(asyncQueue, cmd); + // TODO: Which queue should this be submitted to? + // Should we move all uploads to the worker? + context.cmd.submitOnceAndWait(1, cmd); } + cmd.close(); if (jobs.isEmpty()) { - return;//No jobs to do + return; // No jobs to do } batchedJobs.add(jobs); awaitingJobBatchess.release(); diff --git a/src/main/java/me/cortex/vulkanite/acceleration/AccelerationManager.java b/src/main/java/me/cortex/vulkanite/acceleration/AccelerationManager.java index 0d583cc..cbb8e3e 100644 --- a/src/main/java/me/cortex/vulkanite/acceleration/AccelerationManager.java +++ b/src/main/java/me/cortex/vulkanite/acceleration/AccelerationManager.java @@ -1,6 +1,9 @@ package me.cortex.vulkanite.acceleration; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; +import me.cortex.vulkanite.lib.cmd.VCmdBuff; +import me.cortex.vulkanite.lib.descriptors.VDescriptorSet; import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; import me.cortex.vulkanite.lib.memory.VAccelerationStructure; import me.cortex.vulkanite.lib.memory.VBuffer; @@ -38,7 +41,7 @@ public void setEntityData(List> dat tlasManager.setEntityData(data); } - private final List syncs = new LinkedList<>(); + private final List blasExecutions = new LinkedList<>(); //This updates the tlas internal structure, DOES NOT INCLUDING BUILDING THE TLAS public void updateTick() { @@ -48,44 +51,27 @@ public void updateTick() { while (!blasResults.isEmpty()) { var batch = blasResults.poll(); results.addAll(batch.results()); - syncs.add(batch.semaphore()); + blasExecutions.add(batch.execution()); } tlasManager.updateSections(results); } } - public VAccelerationStructure buildTLAS(VSemaphore inLink, VSemaphore outLink) { - tlasManager.buildTLAS(inLink, outLink, syncs.toArray(new VSemaphore[0])); - syncs.clear(); - return tlasManager.getTlas(); + public VRef buildTLAS(int queueId, VCmdBuff cmd) { + ctx.cmd.queueWaitForExecutions(queueId, blasBuilder.getAsyncQueue(), blasExecutions); + blasExecutions.clear(); + return tlasManager.buildTLAS(cmd); } public void sectionRemove(RenderSection section) { tlasManager.removeSection(section); } - //Cleans up any loose things such as semaphores waiting to be synced etc - public void cleanup() { - //TODO: FIXME: I DONT THINK THIS IS CORRECT OR WORKS, IM STILL LEAKING VRAM MEMORY OUT THE WAZOO WHEN f3+a reloading - ctx.cmd.waitQueueIdle(0); - ctx.cmd.waitQueueIdle(1); - try { - Thread.sleep(250L); - } catch (InterruptedException e) { - e.printStackTrace(); - } - ctx.cmd.waitQueueIdle(0); - ctx.cmd.waitQueueIdle(1); - syncs.forEach(VSemaphore::free); - syncs.clear(); - tlasManager.cleanupTick(); - } - - public long getGeometrySet() { + public VRef getGeometrySet() { return tlasManager.getGeometrySet(); } - public VDescriptorSetLayout getGeometryLayout() { + public VRef getGeometryLayout() { return tlasManager.getGeometryLayout(); } } diff --git a/src/main/java/me/cortex/vulkanite/acceleration/AccelerationTLASManager.java b/src/main/java/me/cortex/vulkanite/acceleration/AccelerationTLASManager.java index 18c5587..6a49e1a 100644 --- a/src/main/java/me/cortex/vulkanite/acceleration/AccelerationTLASManager.java +++ b/src/main/java/me/cortex/vulkanite/acceleration/AccelerationTLASManager.java @@ -3,18 +3,16 @@ //TLAS manager, ingests blas build requests and manages builds and syncs the tlas import com.mojang.blaze3d.systems.RenderSystem; -import me.cortex.vulkanite.client.Vulkanite; +import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.cmd.VCmdBuff; -import me.cortex.vulkanite.lib.cmd.VCommandPool; -import me.cortex.vulkanite.lib.descriptors.DescriptorSetLayoutBuilder; -import me.cortex.vulkanite.lib.descriptors.DescriptorUpdateBuilder; -import me.cortex.vulkanite.lib.descriptors.VDescriptorPool; -import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; +import me.cortex.vulkanite.lib.descriptors.*; import me.cortex.vulkanite.lib.memory.VAccelerationStructure; import me.cortex.vulkanite.lib.memory.VBuffer; -import me.cortex.vulkanite.lib.other.sync.VFence; -import me.cortex.vulkanite.lib.other.sync.VSemaphore; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.RenderLayer; @@ -39,20 +37,26 @@ public class AccelerationTLASManager { private final TLASSectionManager buildDataManager = new TLASSectionManager(); private final VContext context; private final int queue; - private final VCommandPool singleUsePool; - - private final List structuresToRelease = new ArrayList<>(); - - private VAccelerationStructure currentTLAS; + private List> entityData; public AccelerationTLASManager(VContext context, int queue) { this.context = context; this.queue = queue; - this.singleUsePool = context.cmd.createSingleUsePool(); - this.buildDataManager.resizeBindlessSet(0, null); + this.buildDataManager.resizeBindlessSet(0); this.entityBlasBuilder = new EntityBlasBuilder(context); } + private static int roundUpPow2(int v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; + } + // Returns a sync semaphore to chain in the next command submit public void updateSections(List results) { for (var result : results) { @@ -64,38 +68,19 @@ public void updateSections(List results } } - - private List> entityData; public void setEntityData(List> data) { this.entityData = data; } - public void removeSection(RenderSection section) { buildDataManager.remove(section); } // TODO: cleanup, this is very messy // FIXME: in the case of no geometry create an empty tlas or something??? - public void buildTLAS(VSemaphore semIn, VSemaphore semOut, VSemaphore[] blocking) { + public VRef buildTLAS(VCmdBuff cmd) { RenderSystem.assertOnRenderThread(); - singleUsePool.doReleases(); - - if (buildDataManager.sectionCount() == 0) { - if (blocking.length != 0) { - // This case can happen when reloading or some other weird cases, only occurse - // when the world _becomes_ empty for some reason, so just clear all the - // semaphores - // TODO: move to a destroy method or something in AccelerationManager instead of - // here - for (var semaphore : blocking) { - semaphore.free(); - } - } - return; - } - // NOTE: renderLink is required to ensure that we are not overriding memory that // is actively being used for frames // should have a VK_PIPELINE_STAGE_TRANSFER_BIT blocking bit @@ -104,79 +89,50 @@ public void buildTLAS(VSemaphore semIn, VSemaphore semOut, VSemaphore[] blocking // each region is its own geometry input // this is done for performance reasons when updating (adding/removing) sections - - - VkAccelerationStructureGeometryKHR geometry = VkAccelerationStructureGeometryKHR.calloc(stack); - int instances = 0; - var cmd = singleUsePool.createCommandBuffer(); - cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - VFence fence = context.sync.createFence(); - - Pair entityBuild; if (entityData != null) { - entityBuild = entityBlasBuilder.buildBlas(entityData, cmd, fence); - context.sync.addCallback(fence, ()->{ - entityBuild.getLeft().free(); - entityBuild.getRight().free(); - }); - } else { - entityBuild = null; - } + var entityBuild = entityBlasBuilder.buildBlas(entityData, cmd); - { - // TODO: need to sync with respect to updates from gpu memory updates from - // TLASBuildDataManager - // OR SOMETHING CAUSE WITH MULTIPLE FRAMES GOING AT ONCE the gpu state of - // TLASBuildDataManager needs to be synced with - // the current build phase, and the gpu side needs to be updated accoringly and - // synced correctly - - vkCmdPipelineBarrier(cmd.buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - VkMemoryBarrier.calloc(1, stack) - .sType$Default() - .srcAccessMask(0) - .dstAccessMask(VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT), - null, null); - - VkAccelerationStructureInstanceKHR extra = null; - if (entityBuild != null) { - extra = VkAccelerationStructureInstanceKHR.calloc(stack); - extra.mask(~0) - .instanceCustomIndex(0) - .instanceShaderBindingTableRecordOffset(1) - .accelerationStructureReference(entityBuild.getLeft().deviceAddress); - extra.transform().matrix(new Matrix4x3f().getTransposed(stack.mallocFloat(12))); - buildDataManager.descUpdateJobs.add(new TLASSectionManager.DescUpdateJob(0,0, List.of(entityBuild.getRight()))); - instances++; + for (var entityBatch : entityBuild) { + if (entityBatch.offsets().isEmpty()) { + continue; + } + + var entityASI = VkAccelerationStructureInstanceKHR.calloc(stack) + .mask(~0) + .instanceShaderBindingTableRecordOffset(1); + entityASI.transform().matrix(new Matrix4x3f().getTransposed(stack.mallocFloat(12))); + + buildDataManager.addEphemeralInstance(cmd, entityASI, entityBatch.structure(), entityBatch.geometry(), entityBatch.offsets()); + entityBatch.geometry().close(); + entityBatch.structure().close(); } - buildDataManager.setGeometryUpdateMemory(fence, geometry, extra); - instances += buildDataManager.sectionCount(); - - vkCmdPipelineBarrier(cmd.buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, - VkMemoryBarrier.calloc(1, stack) - .sType$Default() - .srcAccessMask(VK_ACCESS_TRANSFER_WRITE_BIT) - .dstAccessMask(VK_ACCESS_SHADER_READ_BIT), - null, null); } + // getInstanceBuffer also builds / updates the geometry desc set + var rets = buildDataManager.getInstanceBuffer(); + var instanceBuffer = rets.getLeft(); + int numInstances = rets.getRight(); - - int[] instanceCounts = new int[]{instances}; - { - geometry.sType$Default() - .geometryType(VK_GEOMETRY_TYPE_INSTANCES_KHR) - .flags(0); - - geometry.geometry() - .instances() - .sType$Default() - .arrayOfPointers(false); + for (var holderRef : buildDataManager.activeSections.values()) { + // Let the cmdbuf manage the lifetime of the holder & desc set entry + cmd.moveRefGeneric(holderRef.addRefGeneric()); } + geometry.sType$Default() + .geometryType(VK_GEOMETRY_TYPE_INSTANCES_KHR) + .flags(0); + + geometry.geometry() + .instances() + .sType$Default() + .arrayOfPointers(false); + + geometry.geometry() + .instances() + .data() + .deviceAddress(instanceBuffer.get().deviceAddress()); // TLAS always rebuild & PREFER_FAST_TRACE according to Nvidia var buildInfo = VkAccelerationStructureBuildGeometryInfoKHR.calloc(1, stack) @@ -191,16 +147,17 @@ public void buildTLAS(VSemaphore semIn, VSemaphore semOut, VSemaphore[] blocking .calloc(stack) .sType$Default(); + int[] instanceCounts = new int[]{numInstances}; vkGetAccelerationStructureBuildSizesKHR( context.device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, buildInfo.get(0), // The reason its a buffer is cause of pain and that - // vkCmdBuildAccelerationStructuresKHR requires a buffer of - // VkAccelerationStructureBuildGeometryInfoKHR + // vkCmdBuildAccelerationStructuresKHR requires a buffer of + // VkAccelerationStructureBuildGeometryInfoKHR stack.ints(instanceCounts), buildSizesInfo); - VAccelerationStructure tlas = context.memory.createAcceleration(buildSizesInfo.accelerationStructureSize(), + var tlas = context.memory.createAcceleration(buildSizesInfo.accelerationStructureSize(), 256, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR, VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR); @@ -209,13 +166,14 @@ public void buildTLAS(VSemaphore semIn, VSemaphore semOut, VSemaphore[] blocking // about that and it should // get automatically freed since we using vma dont have to worry about // performance _too_ much i think - VBuffer scratchBuffer = context.memory.createBuffer(buildSizesInfo.buildScratchSize(), + var scratchBuffer = context.memory.createBuffer(buildSizesInfo.buildScratchSize(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 256, 0); + scratchBuffer.get().setDebugUtilsObjectName("TLAS Scratch Buffer"); - buildInfo.dstAccelerationStructure(tlas.structure) + buildInfo.dstAccelerationStructure(tlas.get().structure) .scratchData(VkDeviceOrHostAddressKHR.calloc(stack) - .deviceAddress(scratchBuffer.deviceAddress())); + .deviceAddress(scratchBuffer.get().deviceAddress())); var buildRanges = VkAccelerationStructureBuildRangeInfoKHR.calloc(instanceCounts.length, stack); for (int count : instanceCounts) { @@ -223,52 +181,66 @@ public void buildTLAS(VSemaphore semIn, VSemaphore semOut, VSemaphore[] blocking } buildRanges.rewind(); - vkCmdBuildAccelerationStructuresKHR(cmd.buffer, + cmd.encodeMemoryBarrier(); + + vkCmdBuildAccelerationStructuresKHR(cmd.buffer(), buildInfo, stack.pointers(buildRanges)); + cmd.addBufferRef(instanceBuffer); + cmd.addBufferRef(scratchBuffer); + instanceBuffer.close(); + scratchBuffer.close(); - cmd.end(); - - int[] waitingStage = new int[blocking.length + 1]; - VSemaphore[] allBlocking = new VSemaphore[waitingStage.length]; - System.arraycopy(blocking, 0, allBlocking, 0, blocking.length); + cmd.encodeMemoryBarrier(); - allBlocking[waitingStage.length - 1] = semIn; + return tlas; + } + } - Arrays.fill(waitingStage, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT); - context.cmd.submit(queue, new VCmdBuff[] { cmd }, allBlocking, waitingStage, new VSemaphore[] { semOut }, - fence); + public VRef getGeometrySet() { + return buildDataManager.geometryBufferDescSet.addRef(); + } - VAccelerationStructure oldTLAS = currentTLAS; - currentTLAS = tlas; + public VRef getGeometryLayout() { + return buildDataManager.geometryBufferSetLayout.addRef(); + } - List capturedList = new ArrayList<>(structuresToRelease); - structuresToRelease.clear(); - context.sync.addCallback(fence, () -> { - scratchBuffer.free(); - if (oldTLAS != null) { - oldTLAS.free(); - } - fence.free(); - cmd.enqueueFree(); + private static final class TlasPointerArena { + private final BitSet vacant; + public int maxIndex = 0; - for (var as : capturedList) { - as.free(); - } + private TlasPointerArena(int size) { + size *= 3; + vacant = new BitSet(size); + vacant.set(0, size); + } - // Release all the semaphores from the blas build system - for (var sem : blocking) { - sem.free(); + public int allocate(int count) { + int pos = vacant.nextSetBit(0); + outer: + while (pos != -1) { + for (int offset = 1; offset < count; offset++) { + if (!vacant.get(offset + pos)) { + pos = vacant.nextSetBit(offset + pos + 1); + continue outer; + } } - }); + break; + } + if (pos == -1) { + throw new IllegalStateException(); + } + vacant.clear(pos, pos + count); + maxIndex = Math.max(maxIndex, pos + count); + return pos; } - } - public VAccelerationStructure getTlas() { - return currentTLAS; - } + public void free(int pos, int count) { + vacant.set(pos, pos + count); + maxIndex = vacant.previousClearBit(maxIndex) + 1; + } + } // Manages entries in the VkAccelerationStructureInstanceKHR buffer, ment to // reuse as much as possible and be very efficient @@ -282,136 +254,151 @@ private class TLASGeometryManager { // Needs a gpu buffer for the instance data, this can be reused // private VkAccelerationStructureInstanceKHR.Buffer buffer; - private VkAccelerationStructureInstanceKHR.Buffer instances = VkAccelerationStructureInstanceKHR.calloc(30000); - private int[] instance2pointer = new int[30000]; - private int[] pointer2instance = new int[30000]; - private BitSet free = new BitSet(30000);// The reason this is needed is to give non used instance ids - private int count; + private final IntArrayFIFOQueue freeIds = new IntArrayFIFOQueue(); + private int maxInstances = 0; + private VkAccelerationStructureInstanceKHR.Buffer instances = null; + private int count = 0; + // This maps each location in the instance buffer to an id + private int[] loc2id = new int[maxInstances]; + // This maps each id to a location in the instance buffer + private int[] id2loc = new int[maxInstances]; public TLASGeometryManager() { - free.set(0, instance2pointer.length); + resize(32768); } - // TODO: make the instances buffer, gpu permenent then stream updates instead of - // uploading per frame - public void setGeometryUpdateMemory(VFence fence, VkAccelerationStructureGeometryKHR struct, VkAccelerationStructureInstanceKHR addin) { - long size = (long) VkAccelerationStructureInstanceKHR.SIZEOF * count; - VBuffer data = context.memory.createBuffer(size + (addin==null?0:VkAccelerationStructureInstanceKHR.SIZEOF), - VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR - | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); - long ptr = data.map(); - if (addin != null) { - MemoryUtil.memCopy(addin.address(), ptr, VkAccelerationStructureInstanceKHR.SIZEOF); - ptr += VkAccelerationStructureInstanceKHR.SIZEOF; - } - MemoryUtil.memCopy(this.instances.address(0), ptr, size); - - data.unmap(); - data.flush(); + public void resize(int newSize) { + if (newSize > maxInstances) { + newSize = roundUpPow2(newSize); + + // Resize the instance buffer + VkAccelerationStructureInstanceKHR.Buffer newBuffer = VkAccelerationStructureInstanceKHR + .calloc(newSize); + if (instances != null) { + newBuffer.put(instances); + newBuffer.rewind(); + instances.free(); + } + instances = newBuffer; - struct.geometry() - .instances() - .data() - .deviceAddress(data.deviceAddress()); + // Add new ids to the free list + for (int i = maxInstances; i < newSize; i++) { + freeIds.enqueue(i); + } - context.sync.addCallback(fence, () -> { - data.free(); - }); - } + // Resize the id mapping arrays + int[] newLoc2Id = new int[newSize]; + int[] newId2Loc = new int[newSize]; + System.arraycopy(loc2id, 0, newLoc2Id, 0, count); + System.arraycopy(id2loc, 0, newId2Loc, 0, count); + loc2id = newLoc2Id; + id2loc = newId2Loc; - public int sectionCount() { - return count; + maxInstances = newSize; + } } - protected int alloc() { - int id = free.nextSetBit(0); + protected int alloc(VkAccelerationStructureInstanceKHR instance) { + // Increment the count + count++; + resize(count); - free.clear(id); + // Get a free id + int id = freeIds.dequeueInt(); - // Update the map - instance2pointer[id] = count; - pointer2instance[count] = id; + // The instances buffer is dense + // Allocation always append to the end + loc2id[count - 1] = id; + id2loc[id] = count - 1; - // Increment the count - count++; + // Copy the instance to the buffer + MemoryUtil.memCopy(instance.address(), instances.address(count - 1), VkAccelerationStructureInstanceKHR.SIZEOF); return id; } protected void free(int id) { - free.set(id); + if (id < 0) { + throw new IllegalArgumentException("Invalid id"); + } + + freeIds.enqueue(id); + + int loc = id2loc[id]; + id2loc[id] = -1; + loc2id[loc] = -1; count--; - if (instance2pointer[id] == count) { - // We are at the end of the pointer list, so just decrement and be done - instance2pointer[id] = -1; - pointer2instance[count] = -1; - } else { - // TODO: CHECK THIS IS CORRECT - - // We need to remove the pointer, and fill it in with the last element in the - // pointer array, updating the mapping of the moved - int ptrId = instance2pointer[id]; - instance2pointer[id] = -1; - - // I feel like this should be pointer2instance = pointer2instance - pointer2instance[ptrId] = pointer2instance[count]; - - // move over the ending data to the missing hole point - MemoryUtil.memCopy(instances.address(count), instances.address(ptrId), + if (loc != count) { + // Move the last element to the hole + int lastId = loc2id[count]; + loc2id[count] = -1; + loc2id[loc] = lastId; + id2loc[lastId] = loc; + MemoryUtil.memCopy(instances.address(count), instances.address(loc), VkAccelerationStructureInstanceKHR.SIZEOF); - - instance2pointer[pointer2instance[count]] = ptrId; } } - protected void update(int id, VkAccelerationStructureInstanceKHR data) { - MemoryUtil.memCopy(data.address(), instances.address(instance2pointer[id]), - VkAccelerationStructureInstanceKHR.SIZEOF); + private final List ephemeralInstances = new ArrayList<>(); + + public void addEphemeralInstance(VkAccelerationStructureInstanceKHR asi) { + var newASI = VkAccelerationStructureInstanceKHR.calloc(); + newASI.set(asi); + ephemeralInstances.add(newASI); } - } - private static int roundUpPow2(int v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; - } + public Pair, Integer> getInstanceBuffer() { + int count = this.count + ephemeralInstances.size(); - private final class TLASSectionManager extends TLASGeometryManager { - private final TlasPointerArena arena = new TlasPointerArena(30000); + long size = VkAccelerationStructureInstanceKHR.SIZEOF * (long) count; + if (size == 0) { + size = VkAccelerationStructureInstanceKHR.SIZEOF; + } + var data = context.memory.createBuffer(size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_MEMORY_HEAP_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + data.get().setDebugUtilsObjectName("TLAS Instance Buffer"); - public TLASSectionManager() { - //Allocate index 0 to entity blas - if (arena.allocate(1) != 0) { - throw new IllegalStateException(); + long persistentSize = VkAccelerationStructureInstanceKHR.SIZEOF * (long) this.count; + long ptr = data.get().map(); + if (persistentSize > 0) { + MemoryUtil.memCopy(this.instances.address(0), ptr, persistentSize); } - } - private VDescriptorSetLayout geometryBufferSetLayout; - private VDescriptorPool geometryBufferDescPool; - private long geometryBufferDescSet = 0; + ptr = ptr + persistentSize; + for (var asi : ephemeralInstances) { + MemoryUtil.memCopy(asi.address(), ptr, VkAccelerationStructureInstanceKHR.SIZEOF); + ptr += VkAccelerationStructureInstanceKHR.SIZEOF; + asi.free(); + } + ephemeralInstances.clear(); - private int setCapacity = 0; + data.get().unmap(); + data.get().flush(); - private record DescUpdateJob(int binding, int dstArrayElement, List buffers) { + return new Pair<>(data, count); } + } - private record ArenaDeallocJob(int index, int count, List geometryBuffers) { - } + private final class TLASSectionManager extends TLASGeometryManager { + private final TlasPointerArena arena = new TlasPointerArena(30000); + private final ConcurrentLinkedDeque sectionUpdates = new ConcurrentLinkedDeque<>(); + private final ConcurrentLinkedDeque sectionRemovals = new ConcurrentLinkedDeque<>(); + private final Map> activeSections = new HashMap<>(); + private final ArrayList descriptorUpdateJobs = new ArrayList<>(); + private VRef geometryBufferSetLayout; + private VRef geometryBufferDescSet = null; + private int setCapacity = 0; - private final ConcurrentLinkedDeque descUpdateJobs = new ConcurrentLinkedDeque<>(); - private final ConcurrentLinkedDeque arenaDeallocJobs = new ConcurrentLinkedDeque<>(); - private final Deque descPoolsToRelease = new ArrayDeque<>(); + public TLASSectionManager() { + super(); + } - public void resizeBindlessSet(int newSize, VFence fence) { + public void resizeBindlessSet(int newSize) { if (geometryBufferSetLayout == null) { var layoutBuilder = new DescriptorSetLayoutBuilder( VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT); @@ -425,29 +412,17 @@ public void resizeBindlessSet(int newSize, VFence fence) { if (newSize > setCapacity) { int newCapacity = roundUpPow2(Math.max(newSize, 32)); - var newGeometryBufferDescPool = new VDescriptorPool(context, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, 1, newCapacity, geometryBufferSetLayout.types); - newGeometryBufferDescPool.allocateSets(geometryBufferSetLayout, new int[] { newCapacity }); - long newGeometryBufferDescSet = newGeometryBufferDescPool.get(0); + var geometryBufferDescPool = VDescriptorPool.create(context, geometryBufferSetLayout, VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, newCapacity); + var newGeometryBufferDescSet = geometryBufferDescPool.get().allocateSet(newCapacity); - System.out.println("New geometry desc set: " + Long.toHexString(newGeometryBufferDescSet) + System.out.println("New geometry desc set: " + Long.toHexString(newGeometryBufferDescSet.get().set) + " with capacity " + newCapacity); - if (geometryBufferDescSet != 0) { - try (var stack = stackPush()) { - var setCopy = VkCopyDescriptorSet.calloc(1, stack); - setCopy.get(0) - .sType$Default() - .srcSet(geometryBufferDescSet) - .dstSet(newGeometryBufferDescSet) - .descriptorCount(setCapacity); - vkUpdateDescriptorSets(context.device, null, setCopy); - } - - descPoolsToRelease.add(geometryBufferDescPool); + if (geometryBufferDescSet != null) { + newGeometryBufferDescSet.get().copyFrom(context, geometryBufferDescSet, setCapacity); + geometryBufferDescSet.close(); } - geometryBufferDescPool = newGeometryBufferDescPool; geometryBufferDescSet = newGeometryBufferDescSet; setCapacity = newCapacity; } @@ -455,165 +430,179 @@ public void resizeBindlessSet(int newSize, VFence fence) { } @Override - public void setGeometryUpdateMemory(VFence fence, VkAccelerationStructureGeometryKHR struct, VkAccelerationStructureInstanceKHR addin) { - super.setGeometryUpdateMemory(fence, struct, addin); - resizeBindlessSet(arena.maxIndex, fence); + public Pair, Integer> getInstanceBuffer() { + HashSet removals = new HashSet<>(); + { + RenderSection section; + while ((section = sectionRemovals.poll()) != null) { + removals.add(section); + } + } - if (descUpdateJobs.isEmpty()) { - return; + // Filter updates to only the latest + HashMap updates = new HashMap<>(); + { + AccelerationBlasBuilder.BLASBuildResult result; + while ((result = sectionUpdates.poll()) != null) { + var data = result.data(); + var section = data.section(); + if (removals.contains(section)) { + // Already removed, close the buffers and continue + result.structure().close(); + data.geometryBuffer().close(); + } else { + // We process the updates sequentially + // Older updates are overwritten + var key = section.getPosition(); + if (updates.containsKey(key)) { + var prev = updates.get(key); + prev.structure().close(); + prev.data().geometryBuffer().close(); + } + updates.put(key, result); + } + } } - var dub = new DescriptorUpdateBuilder(context, descUpdateJobs.size()); - dub.set(geometryBufferDescSet); - while (!descUpdateJobs.isEmpty()) { - var job = descUpdateJobs.poll(); - dub.buffer(job.binding, job.dstArrayElement, job.buffers); + // Process removals + for (var section : removals) { + var prev = activeSections.remove(section.getPosition()); + if (prev != null) { + free(prev.get().id); + prev.close(); + } } - dub.apply(); - // Queue up the arena dealloc jobs to be done after the fence is done - Vulkanite.INSTANCE.addSyncedCallback(() -> { - fenceTick(); - }); - } + int newGeoms = 0; + for (var entry : updates.entrySet()) { + newGeoms += entry.getValue().data().bufferOffsets().size(); + } + resizeBindlessSet(Integer.max(arena.maxIndex + newGeoms, 1024)); + + // Process updates + if (!updates.isEmpty() || !descriptorUpdateJobs.isEmpty()) { + var dub = new DescriptorUpdateBuilder(context, updates.size() + descriptorUpdateJobs.size()); + dub.set(geometryBufferDescSet); + + for (var entry : updates.entrySet()) { + var result = entry.getValue(); + var data = result.data(); + var section = data.section(); + var posKey = section.getPosition(); + + var prevHolder = activeSections.remove(posKey); + if (prevHolder != null) { + free(prevHolder.get().id); + prevHolder.close(); + } - // TODO: mixinto RenderSection and add a reference to a holder for us, its much - // faster than a hashmap - private static final class Holder { - final int id; - int geometryIndex = -1; - List geometryBuffers; + int numGeometriesInInstance = data.bufferOffsets().size(); + int geometryIndex = arena.allocate(numGeometriesInInstance); - final RenderSection section; - VAccelerationStructure structure; + // Add the geometry buffer to the descriptor set (the set retains another reference) + dub.buffer(0, geometryIndex, data.geometryBuffer(), data.bufferOffsets()); + data.geometryBuffer().close(); - private Holder(int id, RenderSection section) { - this.id = id; - this.section = section; - } - } + int id; + try (var stack = stackPush()) { + var asi = VkAccelerationStructureInstanceKHR.calloc(stack) + .mask(~0) + .instanceCustomIndex(geometryIndex) + .accelerationStructureReference(result.structure().get().deviceAddress); + asi.transform() + .matrix(new Matrix4x3f() + .translate(section.getOriginX(), section.getOriginY(), + section.getOriginZ()) + .getTransposed(stack.mallocFloat(12))); + + id = alloc(asi); + } - Map tmp = new HashMap<>(); + // Ownership of result.structure() is transferred to the holder + var holder = Holder.create(id, geometryIndex, numGeometriesInInstance, result.structure(), this); + activeSections.put(section.getPosition(), holder); + } - public void fenceTick() { - while (!arenaDeallocJobs.isEmpty()) { - var job = arenaDeallocJobs.poll(); - arena.free(job.index, job.count); - job.geometryBuffers.forEach(buffer -> buffer.free()); - } - while (!descPoolsToRelease.isEmpty()) { - descPoolsToRelease.poll().free(); + for (var job : descriptorUpdateJobs) { + dub.buffer(0, job.element, job.geometryBuffer, job.bufferOffsets); + job.geometryBuffer.close(); + } + descriptorUpdateJobs.clear(); + + dub.apply(); } + + return super.getInstanceBuffer(); } - public void update(AccelerationBlasBuilder.BLASBuildResult result) { - var data = result.data(); - var holder = tmp.computeIfAbsent(data.section().getPosition(), a -> new Holder(alloc(), data.section())); - if (holder.structure != null) { - structuresToRelease.add(holder.structure); + private void arenaFree(int index, int count) { + arena.free(index, count); + for (int i = 0; i < count; i++) { + geometryBufferDescSet.get().removeRef(index + i); } - holder.structure = result.structure(); + } - if (holder.geometryIndex != -1) { - arenaDeallocJobs.add(new ArenaDeallocJob(holder.geometryIndex, holder.geometryBuffers.size(), - holder.geometryBuffers)); - } - holder.geometryBuffers = data.geometryBuffers(); - holder.geometryIndex = arena.allocate(holder.geometryBuffers.size()); - - descUpdateJobs.add(new DescUpdateJob(0, holder.geometryIndex, holder.geometryBuffers)); - - try (var stack = stackPush()) { - var asi = VkAccelerationStructureInstanceKHR.calloc(stack) - .mask(~0) - .instanceCustomIndex(holder.geometryIndex) - .accelerationStructureReference(holder.structure.deviceAddress); - asi.transform() - .matrix(new Matrix4x3f() - .translate(holder.section.getOriginX(), holder.section.getOriginY(), - holder.section.getOriginZ()) - .getTransposed(stack.mallocFloat(12))); - update(holder.id, asi); - } + public void update(AccelerationBlasBuilder.BLASBuildResult result) { + sectionUpdates.add(result); } public void remove(RenderSection section) { - var holder = tmp.remove(section.getPosition()); - if (holder == null) - return; + sectionRemovals.add(section); + } - structuresToRelease.add(holder.structure); + public void addEphemeralInstance(VCmdBuff cmd, VkAccelerationStructureInstanceKHR asi, final VRef structure, final VRef geometryBuffer, List bufferOffsets) { + if (bufferOffsets.isEmpty()) { + return; + } - free(holder.id); + int numGeometries = bufferOffsets.size(); + int geometryIndex = arena.allocate(bufferOffsets.size()); - for (var job : descUpdateJobs) { - if (job.buffers == holder.geometryBuffers) { - descUpdateJobs.remove(job); - } - } + asi.accelerationStructureReference(structure.get().deviceAddress); + asi.instanceCustomIndex(geometryIndex); - if (holder.geometryIndex != -1) { - arenaDeallocJobs.add(new ArenaDeallocJob(holder.geometryIndex, holder.geometryBuffers.size(), - holder.geometryBuffers)); - } - } - } + addEphemeralInstance(asi); - private static final class TlasPointerArena { - private final BitSet vacant; - public int maxIndex = 0; + var holder = Holder.create(-1, geometryIndex, numGeometries, structure.addRef(), this); + cmd.moveRefGeneric(holder.addRefGeneric()); + holder.close(); - private TlasPointerArena(int size) { - size *= 3; - vacant = new BitSet(size); - vacant.set(0, size); + descriptorUpdateJobs.add(new DescriptorUpdateJob(geometryIndex, geometryBuffer.addRef(), bufferOffsets)); } - public int allocate(int count) { - int pos = vacant.nextSetBit(0); - outer: while (pos != -1) { - for (int offset = 1; offset < count; offset++) { - if (!vacant.get(offset + pos)) { - pos = vacant.nextSetBit(offset + pos + 1); - continue outer; - } - } - break; - } - if (pos == -1) { - throw new IllegalStateException(); - } - vacant.clear(pos, pos + count); - maxIndex = Math.max(maxIndex, pos + count); - return pos; + public record DescriptorUpdateJob(int element, VRef geometryBuffer, List bufferOffsets) { } - public void free(int pos, int count) { - vacant.set(pos, pos + count); + // TODO: mixinto RenderSection and add a reference to a holder for us, its much + // faster than a hashmap + private static final class Holder extends VObject { + // A holder holds (duh) a section and its associated data + // The data might currently be in use by the gpu - maxIndex = vacant.previousClearBit(maxIndex) + 1; - } - } + final int id; + final TLASSectionManager manager; + final int geometryIndex; + final int numGeometries; + final VRef structure; - public long getGeometrySet() { - return buildDataManager.geometryBufferDescSet; - } + private Holder(int id, int geometryIndex, int numGeometries, VRef structure, TLASSectionManager manager) { + this.id = id; + this.geometryIndex = geometryIndex; + this.numGeometries = numGeometries; + this.structure = structure; + this.manager = manager; + } - public VDescriptorSetLayout getGeometryLayout() { - return buildDataManager.geometryBufferSetLayout; - } + public static VRef create(int id, int geometryIndex, int numGeometries, VRef structure, TLASSectionManager manager) { + return new VRef<>(new Holder(id, geometryIndex, numGeometries, structure, manager)); + } - // Called for cleaning up any remaining loose resources - void cleanupTick() { - singleUsePool.doReleases(); - structuresToRelease.forEach(VAccelerationStructure::free); - structuresToRelease.clear(); - if (currentTLAS != null) { - currentTLAS.free(); - currentTLAS = null; - } - if (buildDataManager.sectionCount() != 0) { - throw new IllegalStateException("Sections are not empty on cleanup"); + @Override + protected void free() { + structure.close(); + // This removes it from the geometry buffer & descriptor set + manager.arenaFree(geometryIndex, numGeometries); + } } } } diff --git a/src/main/java/me/cortex/vulkanite/acceleration/EntityBlasBuilder.java b/src/main/java/me/cortex/vulkanite/acceleration/EntityBlasBuilder.java index be44244..0a6edd4 100644 --- a/src/main/java/me/cortex/vulkanite/acceleration/EntityBlasBuilder.java +++ b/src/main/java/me/cortex/vulkanite/acceleration/EntityBlasBuilder.java @@ -2,12 +2,12 @@ import me.cortex.vulkanite.compat.IVGImage; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.cmd.VCmdBuff; import me.cortex.vulkanite.lib.memory.VAccelerationStructure; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.other.VUtil; -import me.cortex.vulkanite.lib.other.sync.VFence; -import net.coderbot.iris.vertices.IrisVertexFormats; +import net.irisshaders.iris.vertices.IrisVertexFormats; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.RenderLayer; @@ -22,32 +22,84 @@ import java.util.ArrayList; import java.util.List; -import static org.lwjgl.util.vma.Vma.VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; +import static org.lwjgl.util.vma.Vma.VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; import static org.lwjgl.vulkan.KHRAccelerationStructure.*; -import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; import static org.lwjgl.vulkan.KHRBufferDeviceAddress.VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; import static org.lwjgl.vulkan.VK10.*; public class EntityBlasBuilder { private final VContext ctx; + public EntityBlasBuilder(VContext context) { this.ctx = context; } - private record BuildInfo(VertexFormat format, int quadCount, long address) {} - Pair buildBlas(List> renders, VCmdBuff cmd, VFence fence) { + private static VRef executeBlasBuild(VContext ctx, VCmdBuff cmd, MemoryStack stack, VkAccelerationStructureGeometryKHR.Buffer geometryInfos, int[] prims) { + var buildInfos = VkAccelerationStructureBuildGeometryInfoKHR.calloc(1, stack); + var buildRanges = VkAccelerationStructureBuildRangeInfoKHR.calloc(prims.length, stack); + for (int primCount : prims) { + buildRanges.get().primitiveCount(primCount); + } + + var bi = buildInfos.get() + .sType$Default() + .type(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) + .flags(VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR) + .pGeometries(geometryInfos) + .geometryCount(geometryInfos.remaining()); + + VkAccelerationStructureBuildSizesInfoKHR buildSizesInfo = VkAccelerationStructureBuildSizesInfoKHR + .calloc(stack) + .sType$Default(); + + vkGetAccelerationStructureBuildSizesKHR( + ctx.device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + bi, + prims, + buildSizesInfo); + + + var structure = ctx.memory.createAcceleration(buildSizesInfo.accelerationStructureSize(), 256, + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); + + var scratch = ctx.memory.createBuffer(buildSizesInfo.buildScratchSize(), + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 256, 0); + + bi.scratchData(VkDeviceOrHostAddressKHR.calloc(stack).deviceAddress(scratch.get().deviceAddress())); + bi.dstAccelerationStructure(structure.get().structure); + + buildInfos.rewind(); + buildRanges.rewind(); + + vkCmdBuildAccelerationStructuresKHR(cmd.buffer(), buildInfos, stack.pointers(buildRanges)); + + vkCmdPipelineBarrier(cmd.buffer(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, VkMemoryBarrier.calloc(1, stack) + .sType$Default() + .srcAccessMask(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR) + .dstAccessMask(VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR), null, null); + + cmd.addAccelerationStructureRef(structure); + cmd.addBufferRef(scratch); + scratch.close(); + + return structure; + } + + List buildBlas(List> renders, VCmdBuff cmd) { long combined_size = 0; TextureManager textureManager = MinecraftClient.getInstance().getTextureManager(); for (var type : renders) { - if (((RenderLayer.MultiPhase)type.getLeft()).phases.texture instanceof RenderPhase.Textures) { - throw new IllegalStateException("Multi texture not supported"); - } - var textureId = ((RenderLayer.MultiPhase)type.getLeft()).phases.texture.getId().get(); - var texture = textureManager.getTexture(textureId); - var vkImage = ((IVGImage)texture).getVGImage(); - if (vkImage == null) { - throw new IllegalStateException("Vulkan texture not created for render layer " + type.getLeft()); - } +// if (((RenderLayer.MultiPhase) type.getLeft()).phases.texture instanceof RenderPhase.Textures) { +// throw new IllegalStateException("Multi texture not supported"); +// } +// var textureId = ((RenderLayer.MultiPhase) type.getLeft()).phases.texture.getId().get(); +// var texture = textureManager.getTexture(textureId); +// var vkImage = ((IVGImage) texture).getVGImage(); +// if (vkImage == null) { +// throw new IllegalStateException("Vulkan texture not created for render layer " + type.getLeft()); +// } if (!type.getRight().getParameters().format().equals(IrisVertexFormats.ENTITY)) { throw new IllegalStateException("Unknown vertex format used"); } @@ -56,37 +108,52 @@ Pair buildBlas(List infos = new ArrayList<>(); + List offsets = new ArrayList<>(); for (var pair : renders) { offset = VUtil.alignUp(offset, 128); MemoryUtil.memCopy(MemoryUtil.memAddress(pair.getRight().getVertexBuffer()), ptr + offset, pair.getRight().getVertexBuffer().remaining()); - infos.add(new BuildInfo(pair.getRight().getParameters().format(), pair.getRight().getParameters().indexCount()/6, geometryBuffer.deviceAddress() + offset)); - + infos.add(new BuildInfo(pair.getRight().getParameters().format(), pair.getRight().getParameters().indexCount() / 6, geometryBuffer.get().deviceAddress() + offset)); + offsets.add(offset); offset += pair.getRight().getVertexBuffer().remaining(); } - geometryBuffer.unmap(); + cmd.addBufferRef(geometryBufferStaging); + geometryBufferStaging.get().unmap(); + + cmd.encodeBufferCopy(geometryBufferStaging, 0, geometryBuffer, 0, combined_size); + cmd.encodeBufferBarrier(geometryBuffer, 0, combined_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + geometryBufferStaging.close(); - VAccelerationStructure blas = null; + VRef blas; try (var stack = MemoryStack.stackPush()) { int[] primitiveCounts = new int[infos.size()]; var buildInfo = populateBuildStructs(ctx, stack, cmd, infos, primitiveCounts); - blas = executeBlasBuild(ctx, cmd, fence, stack, buildInfo, primitiveCounts); + blas = executeBlasBuild(ctx, cmd, stack, buildInfo, primitiveCounts); } - - return new Pair<>(blas, geometryBuffer); + return List.of(new BLASResult(blas, geometryBuffer, offsets)); } private VkAccelerationStructureGeometryKHR.Buffer populateBuildStructs(VContext ctx, MemoryStack stack, VCmdBuff cmdBuff, List geometries, int[] primitiveCounts) { var geometryInfos = VkAccelerationStructureGeometryKHR.calloc(geometries.size(), stack); int i = 0; for (var geometry : geometries) { - VkDeviceOrHostAddressConstKHR indexData = SharedQuadVkIndexBuffer.getIndexBuffer(ctx, cmdBuff, geometry.quadCount); + var indexBuffer = SharedQuadVkIndexBuffer.getIndexBuffer(ctx, cmdBuff, geometry.quadCount); + VkDeviceOrHostAddressConstKHR indexData = indexBuffer.get().deviceAddressConst(); int indexType = SharedQuadVkIndexBuffer.TYPE; VkDeviceOrHostAddressConstKHR vertexData = VkDeviceOrHostAddressConstKHR.calloc(stack).deviceAddress(geometry.address); @@ -109,59 +176,18 @@ private VkAccelerationStructureGeometryKHR.Buffer populateBuildStructs(VContext .geometryType(VK_GEOMETRY_TYPE_TRIANGLES_KHR) // .flags(geometry.geometryFlags) ; + primitiveCounts[i++] = (geometry.quadCount * 2); + + cmdBuff.addBufferRef(indexBuffer); } geometryInfos.rewind(); return geometryInfos; } - private static VAccelerationStructure executeBlasBuild(VContext ctx, VCmdBuff cmd, VFence cleanupFence, MemoryStack stack, VkAccelerationStructureGeometryKHR.Buffer geometryInfos, int[] prims) { - var buildInfos = VkAccelerationStructureBuildGeometryInfoKHR.calloc(1, stack); - var buildRanges = VkAccelerationStructureBuildRangeInfoKHR.calloc(prims.length, stack); - for (int primCount : prims) { - buildRanges.get().primitiveCount(primCount); - } - - var bi = buildInfos.get() - .sType$Default() - .type(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) - .flags(VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR) - .pGeometries(geometryInfos) - .geometryCount(geometryInfos.remaining()); - - VkAccelerationStructureBuildSizesInfoKHR buildSizesInfo = VkAccelerationStructureBuildSizesInfoKHR - .calloc(stack) - .sType$Default(); - - vkGetAccelerationStructureBuildSizesKHR( - ctx.device, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, - bi, - prims, - buildSizesInfo); - - - var structure = ctx.memory.createAcceleration(buildSizesInfo.accelerationStructureSize(), 256, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); - - var scratch = ctx.memory.createBuffer(buildSizesInfo.buildScratchSize(), - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 256, 0); - - bi.scratchData(VkDeviceOrHostAddressKHR.calloc(stack).deviceAddress(scratch.deviceAddress())); - bi.dstAccelerationStructure(structure.structure); - - buildInfos.rewind(); - buildRanges.rewind(); - - vkCmdBuildAccelerationStructuresKHR(cmd.buffer, buildInfos, stack.pointers(buildRanges)); - - vkCmdPipelineBarrier(cmd.buffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, VkMemoryBarrier.calloc(1) - .sType$Default() - .srcAccessMask(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR) - .dstAccessMask(VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR), null, null); + public record BLASResult(VRef structure, VRef geometry, List offsets) { + } - ctx.sync.addCallback(cleanupFence, scratch::free); - return structure; + private record BuildInfo(VertexFormat format, int quadCount, long address) { } } diff --git a/src/main/java/me/cortex/vulkanite/acceleration/GeometryRayFlags.java b/src/main/java/me/cortex/vulkanite/acceleration/GeometryRayFlags.java new file mode 100644 index 0000000..343d1a7 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/acceleration/GeometryRayFlags.java @@ -0,0 +1,14 @@ +package me.cortex.vulkanite.acceleration; + +public enum GeometryRayFlags { + OPAQUE(1), + TRANSPARENT(1 << 1), + ENTITY(1 << 2), + PLAYER(1 << 7), + ; + final int flag; + + GeometryRayFlags(int i) { + flag = i; + } +} diff --git a/src/main/java/me/cortex/vulkanite/acceleration/JobPassThroughData.java b/src/main/java/me/cortex/vulkanite/acceleration/JobPassThroughData.java index d54d4c2..1d91950 100644 --- a/src/main/java/me/cortex/vulkanite/acceleration/JobPassThroughData.java +++ b/src/main/java/me/cortex/vulkanite/acceleration/JobPassThroughData.java @@ -1,10 +1,11 @@ package me.cortex.vulkanite.acceleration; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VBuffer; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import java.util.List; -public record JobPassThroughData(RenderSection section, long time, List geometryBuffers) { +public record JobPassThroughData(RenderSection section, long time, VRef geometryBuffer, List bufferOffsets) { } diff --git a/src/main/java/me/cortex/vulkanite/acceleration/SharedQuadVkIndexBuffer.java b/src/main/java/me/cortex/vulkanite/acceleration/SharedQuadVkIndexBuffer.java index 26051ca..60fee33 100644 --- a/src/main/java/me/cortex/vulkanite/acceleration/SharedQuadVkIndexBuffer.java +++ b/src/main/java/me/cortex/vulkanite/acceleration/SharedQuadVkIndexBuffer.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.acceleration; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.cmd.VCmdBuff; import me.cortex.vulkanite.lib.memory.VBuffer; import org.lwjgl.system.MemoryUtil; @@ -15,25 +16,18 @@ public class SharedQuadVkIndexBuffer { public static final int TYPE = VK_INDEX_TYPE_UINT32; - private static VBuffer indexBuffer = null; - private static VkDeviceOrHostAddressConstKHR indexBufferAddr = null; + private static VRef indexBuffer = null; private static int currentQuadCount = 0; - public synchronized static VkDeviceOrHostAddressConstKHR getIndexBuffer(VContext context, VCmdBuff uploaCmdBuff, int quadCount) { + public synchronized static VRef getIndexBuffer(VContext context, VCmdBuff uploaCmdBuff, int quadCount) { if (currentQuadCount < quadCount) { makeNewIndexBuffer(context, uploaCmdBuff, quadCount); } - return indexBufferAddr; + return indexBuffer.addRef(); } private static void makeNewIndexBuffer(VContext context, VCmdBuff uploaCmdBuff, int quadCount) { - if (indexBuffer != null) { - //TODO: need to enqueue the old indexBuffer for memory release - indexBufferAddr.free();//Note this is calloced (in global heap) so need to release it IS SEPERATE FROM indexBuffer - throw new IllegalStateException(); - } - ByteBuffer buffer = genQuadIdxs(quadCount); //TODO: dont harcode VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR and VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT indexBuffer = context.memory.createBuffer(buffer.remaining(), @@ -41,11 +35,11 @@ private static void makeNewIndexBuffer(VContext context, VCmdBuff uploaCmdBuff, | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT); + indexBuffer.get().setDebugUtilsObjectName("Geometry Index Buffer"); uploaCmdBuff.encodeDataUpload(context.memory, MemoryUtil.memAddress(buffer), indexBuffer, 0, buffer.remaining()); - indexBufferAddr = VkDeviceOrHostAddressConstKHR.calloc().deviceAddress(indexBuffer.deviceAddress()); currentQuadCount = quadCount; } diff --git a/src/main/java/me/cortex/vulkanite/client/Test.java b/src/main/java/me/cortex/vulkanite/client/Test.java index ad5c2e0..e0a9af4 100644 --- a/src/main/java/me/cortex/vulkanite/client/Test.java +++ b/src/main/java/me/cortex/vulkanite/client/Test.java @@ -8,7 +8,10 @@ import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GL45; +import org.lwjgl.opengl.GL45C; import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.VkPhysicalDeviceAccelerationStructureFeaturesKHR; import org.lwjgl.vulkan.VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; import org.lwjgl.vulkan.VkPhysicalDeviceRayQueryFeaturesKHR; @@ -17,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.nio.IntBuffer; +import java.nio.LongBuffer; import java.nio.file.Files; import java.util.List; @@ -102,30 +106,83 @@ public static void main(String[] args) throws IOException { .sType$Default() .rayTracingPipeline(true) .rayTracingPipelineTraceRaysIndirect(true) + ), List.of( + s-> {}, + s-> {}, + s-> {}, + s-> {} )); var context = init.createContext(); context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).free(); - context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).free(); - context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).free(); - context.memory.createSharedImage(128,128, 1, VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).free(); - context.memory.createSharedImage(128,128, 1, VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).free(); - context.memory.createSharedImage(128,128, 1, VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).free(); - context.memory.createAcceleration(100*256,256, 0, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR).free(); + context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.memory.createSharedBuffer(1000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.memory.createSharedImage(128,128, 1, VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.memory.createSharedImage(128,128, 1, VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.memory.createSharedImage(128,128, 1, VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.memory.createAcceleration(100*256,256, 0, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR); var pool = context.cmd.createSingleUsePool(); - pool.createCommandBuffer(); + pool.get().createCommandBuffer(); - var mem = context.memory.createBuffer(1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0, + var mem = context.memory.createBuffer(1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); - mem.map(); - mem.unmap(); - mem.flush(); + mem.get().map(); + mem.get().unmap(); + mem.get().flush(); System.gc(); // SharedQuadVkIndexBuffer.getIndexBuffer(context, uploadCmd, 10000); + var srcBeegThing = MemoryUtil.nmemCalloc(2L << 30L, 1); + MemoryUtil.memSet(srcBeegThing, 35, 2L << 30L); + + var fmlBuffer0 = context.memory.createBuffer(2L << 30L, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.cmd.executeWait(cmd -> { + cmd.encodeDataUpload(context.memory, srcBeegThing, fmlBuffer0, 0, 2L << 30L); + }); + + var fmlBuffer1 = context.memory.createBuffer(2L << 30L, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.cmd.executeWait(cmd -> { + cmd.encodeDataUpload(context.memory, srcBeegThing, fmlBuffer1, 0, 2L << 30L); + }); + + var fmlBuffer2 = context.memory.createBuffer(2L << 30L, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.cmd.executeWait(cmd -> { + cmd.encodeDataUpload(context.memory, srcBeegThing, fmlBuffer2, 0, 2L << 30L); + }); + + var fmlBuffer3 = context.memory.createBuffer(2L << 30L, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.cmd.executeWait(cmd -> { + cmd.encodeDataUpload(context.memory, srcBeegThing, fmlBuffer3, 0, 2L << 30L); + }); + + var fmlBuffer4 = context.memory.createBuffer(2L << 30L, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + context.cmd.executeWait(cmd -> { + cmd.encodeDataUpload(context.memory, srcBeegThing, fmlBuffer4, 0, 2L << 30L); + }); + + + int glBeegBuf = GL45.glCreateBuffers(); + GL45C.glNamedBufferData(glBeegBuf, 2L << 30L, GL45C.GL_STATIC_DRAW); + GL45C.glBindBufferBase(GL45C.GL_SHADER_STORAGE_BUFFER, 0, glBeegBuf); + + var beegData = LongBuffer.allocate(2 << 30); + beegData.array()[4] = 69; + GL45C.glNamedBufferSubData(glBeegBuf, 0, beegData); + + MemoryUtil.nmemFree(srcBeegThing); var layout = new DescriptorSetLayoutBuilder() .binding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL)//camera data @@ -140,13 +197,12 @@ public static void main(String[] args) throws IOException { var rchs = VShader.compileLoad(context, Files.readString(new File("run/raychit.glsl").toPath()), VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); var pipeline = new RaytracePipelineBuilder() .addLayout(layout) - .setRayGen(rgs.named()) - .addMiss(rms.named()) - .addHit(rchs.named(), null, null) + .setRayGen(rgs.get().named()) + .addMiss(rms.get().named()) + .addHit(rchs.get().named(), null, null) .build(context, 1); - context.sync.createSharedBinarySemaphore() - .free(); + context.sync.createSharedBinarySemaphore(); var cl = new DescriptorSetLayoutBuilder() @@ -155,7 +211,7 @@ public static void main(String[] args) throws IOException { var compute = VShader.compileLoad(context, Files.readString(new File("run/compute.glsl").toPath()), VK_SHADER_STAGE_COMPUTE_BIT); var comppipe = new ComputePipelineBuilder() - .set(compute.named()) + .set(compute.get().named()) .addLayout(cl) .build(context); diff --git a/src/main/java/me/cortex/vulkanite/client/Vulkanite.java b/src/main/java/me/cortex/vulkanite/client/Vulkanite.java index 31f2fe2..a2d2460 100644 --- a/src/main/java/me/cortex/vulkanite/client/Vulkanite.java +++ b/src/main/java/me/cortex/vulkanite/client/Vulkanite.java @@ -1,28 +1,23 @@ package me.cortex.vulkanite.client; import me.cortex.vulkanite.acceleration.AccelerationManager; -import me.cortex.vulkanite.acceleration.SharedQuadVkIndexBuffer; -import me.cortex.vulkanite.client.rendering.VulkanPipeline; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.base.initalizer.VInitializer; import me.cortex.vulkanite.lib.descriptors.VDescriptorPool; import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; -import me.cortex.vulkanite.lib.descriptors.VTypedDescriptorPool; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import net.minecraft.util.Util; +import org.lwjgl.opengl.GL20; import org.lwjgl.vulkan.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import static org.lwjgl.vulkan.EXTDebugUtils.VK_EXT_DEBUG_UTILS_EXTENSION_NAME; import static org.lwjgl.vulkan.EXTDescriptorIndexing.VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME; -import static org.lwjgl.vulkan.KHR16bitStorage.VK_KHR_16BIT_STORAGE_EXTENSION_NAME; -import static org.lwjgl.vulkan.KHR8bitStorage.VK_KHR_8BIT_STORAGE_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME; -import static org.lwjgl.vulkan.KHRBufferDeviceAddress.VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRDeferredHostOperations.VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRExternalFenceCapabilities.VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRExternalFenceFd.VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME; @@ -37,27 +32,40 @@ import static org.lwjgl.vulkan.KHRExternalSemaphoreWin32.VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRGetMemoryRequirements2.VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRGetPhysicalDeviceProperties2.VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; -import static org.lwjgl.vulkan.KHRRayQuery.VK_KHR_RAY_QUERY_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRRayTracingPipeline.VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRShaderDrawParameters.VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME; import static org.lwjgl.vulkan.KHRSpirv14.VK_KHR_SPIRV_1_4_EXTENSION_NAME; +import static org.lwjgl.vulkan.VK10.vkDeviceWaitIdle; public class Vulkanite { public static final boolean IS_WINDOWS = Util.getOperatingSystem() == Util.OperatingSystem.WINDOWS; - public static boolean MEMORY_LEAK_TRACING = true; - public static boolean IS_ENABLED = true; - public static final Vulkanite INSTANCE = new Vulkanite(); + public static Vulkanite INSTANCE = new Vulkanite(); + public final boolean IS_ZINK; private final VContext ctx; private final ArbitarySyncPointCallback fencedCallback = new ArbitarySyncPointCallback(); private final AccelerationManager accelerationManager; - private final HashMap descriptorPools = new HashMap<>(); + private final HashMap> descriptorPools = new HashMap<>(); public Vulkanite() { ctx = createVulkanContext(); + // Hack: so that AccelerationManager can access Vulkanite.INSTANCE + INSTANCE = this; + + // Check GL_VENDOR to determine if Zink is being used + final var gl_vendor = GL20.glGetString(GL20.GL_VENDOR); + final var gl_renderer = GL20.glGetString(GL20.GL_RENDERER); + if (gl_vendor == null || gl_renderer == null) { + IS_ZINK = false; + } else { + IS_ZINK = gl_vendor.contains("Mesa") && gl_renderer.contains("zink"); + if (IS_ZINK) { + System.out.println("Zink GL detected"); + } + } //Fill in the shared index buffer with a large count so we (hopefully) dont have to worry about it anymore // SharedQuadVkIndexBuffer.getIndexBuffer(ctx, 30000); @@ -75,21 +83,19 @@ public void upload(List results) { accelerationManager.chunkBuilds(results); } - public VTypedDescriptorPool getPoolByLayout(VDescriptorSetLayout layout) { + public VRef getPoolByLayout(VRef layout) { + var key = layout.get(); synchronized (descriptorPools) { - if (!descriptorPools.containsKey(layout)) { - descriptorPools.put(layout, new VTypedDescriptorPool(ctx, layout, 0)); + if (!descriptorPools.containsKey(key)) { + descriptorPools.put(key, VDescriptorPool.create(ctx, layout, 0)); } - return descriptorPools.get(layout); + return descriptorPools.get(key).addRef(); } } public void removePoolByLayout(VDescriptorSetLayout layout) { synchronized (descriptorPools) { - if (descriptorPools.containsKey(layout)) { - descriptorPools.get(layout).free(); - descriptorPools.remove(layout); - } + descriptorPools.remove(layout); } } @@ -115,10 +121,8 @@ public void addSyncedCallback(Runnable callback) { } public void destroy() { - for (var pool : descriptorPools.values()) { - pool.free(); - } - accelerationManager.cleanup(); + vkDeviceWaitIdle(ctx.device); + descriptorPools.clear(); } private static VContext createVulkanContext() { @@ -149,6 +153,8 @@ private static VContext createVulkanContext() { VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, +// VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, + VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME )); if (IS_WINDOWS) { @@ -175,6 +181,18 @@ private static VContext createVulkanContext() { stack-> VkPhysicalDeviceVulkan12Features.calloc(stack) .sType$Default() + ), List.of( + features-> {}, + features -> {}, + features -> { + var vulkan11Features = (VkPhysicalDeviceVulkan11Features) features; + vulkan11Features.protectedMemory(false); + }, + features -> { + var vulkan12Features = (VkPhysicalDeviceVulkan12Features) features; + vulkan12Features.bufferDeviceAddressMultiDevice(false); +// vulkan12Features.bufferDeviceAddressCaptureReplay(false); + } )); return init.createContext(); diff --git a/src/main/java/me/cortex/vulkanite/client/rendering/EntityCapture.java b/src/main/java/me/cortex/vulkanite/client/rendering/EntityCapture.java index 1f7f672..56ab91b 100644 --- a/src/main/java/me/cortex/vulkanite/client/rendering/EntityCapture.java +++ b/src/main/java/me/cortex/vulkanite/client/rendering/EntityCapture.java @@ -8,23 +8,23 @@ import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.other.VUtil; import me.cortex.vulkanite.lib.other.sync.VFence; -import net.coderbot.iris.mixin.LevelRendererAccessor; -import net.coderbot.iris.vertices.IrisVertexFormats; +import net.irisshaders.iris.layer.OuterWrappedRenderType; +import net.irisshaders.iris.mixin.LevelRendererAccessor; +import net.irisshaders.iris.vertices.IrisVertexFormats; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.*; import net.minecraft.client.texture.TextureManager; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.entity.Entity; import net.minecraft.util.Pair; import net.minecraft.world.World; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.lwjgl.util.vma.Vma.VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; import static org.lwjgl.vulkan.KHRAccelerationStructure.*; @@ -84,12 +84,28 @@ public List> end() { //TODO: Doesnt support terrian vertex format yet, requires a second blas so that the instance offset can be the same // as terrain instance offset if (builtBuffer.getParameters().format().equals(IrisVertexFormats.TERRAIN)) { + System.out.println("Skipping block entities (TERRAIN format)"); return; } - //Dont support no texture things - if (((RenderLayer.MultiPhase)layer).phases.texture.getId().isEmpty()) { + + // TODO: Support anything other than ENTITY + if (!builtBuffer.getParameters().format().equals(IrisVertexFormats.ENTITY)) { + System.out.println("Skipping non-Entity format: " + builtBuffer.getParameters().format().toString()); return; } + + //Dont support no texture things +// if (!(layer instanceof OuterWrappedRenderType)) { +// System.out.println("Skipping render layer that's not a MultiPhase, is " + layer.getClass().getName() + " instead"); +// return; +// } +// +// var texture = ((RenderLayer.MultiPhase)layer).phases.texture; +// if ((texture == null) || (texture.getId().isEmpty())) { +// System.out.println("Skipping render layer with no texture"); +// return; +// } + buffers.add(new Pair<>(layer, builtBuffer)); } }); diff --git a/src/main/java/me/cortex/vulkanite/client/rendering/SharedImageViewTracker.java b/src/main/java/me/cortex/vulkanite/client/rendering/SharedImageViewTracker.java index 9435642..6e39a6a 100644 --- a/src/main/java/me/cortex/vulkanite/client/rendering/SharedImageViewTracker.java +++ b/src/main/java/me/cortex/vulkanite/client/rendering/SharedImageViewTracker.java @@ -2,6 +2,8 @@ import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; +import me.cortex.vulkanite.lib.memory.VGImage; import me.cortex.vulkanite.lib.memory.VImage; import me.cortex.vulkanite.lib.other.VImageView; @@ -9,44 +11,35 @@ public class SharedImageViewTracker { private final VContext ctx; - private final Supplier supplier; - private VImageView view; - public SharedImageViewTracker(VContext ctx, Supplier imageSupplier) { + private final Supplier> supplier; + private VRef view; + public SharedImageViewTracker(VContext ctx, Supplier> imageSupplier) { this.supplier = imageSupplier; this.ctx = ctx; } //NOTE: getting the image doesnt invalidate/check for a different image - public VImage getImage() { + public VRef getImage() { if (view != null) { - return view.image; + return view.get().image.addRef(); } return null; } - public VImageView getView() { + public VRef getView() { return getView(this.supplier); } - public VImageView getView(Supplier imageSupplier) { - VImage image = imageSupplier.get(); - if (this.view == null || this.view.image != image) { + public VRef getView(Supplier> imageSupplier) { + VRef image = imageSupplier.get(); + if (view == null || (!view.get().isDerivedFrom(image.get()))) { //TODO: move this to like a fence free that you pass in via an arg - if (view != null) { - Vulkanite.INSTANCE.addSyncedCallback(view::free); - view = null; - } if (image != null) { - this.view = new VImageView(ctx, image); + view = VImageView.create(ctx, new VRef<>(image.get())); + } else { + view = null; } } - return view; - } - - public void free() { - if (view != null) { - Vulkanite.INSTANCE.addSyncedCallback(view::free); - view = null; - } + return view == null ? null : view.addRef(); } } 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 20d435a..f8cc1f2 100644 --- a/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java +++ b/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java @@ -6,26 +6,31 @@ import me.cortex.vulkanite.compat.IVGImage; import me.cortex.vulkanite.compat.RaytracingShaderSet; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; +import me.cortex.vulkanite.lib.base.VRegistry; import me.cortex.vulkanite.lib.cmd.VCmdBuff; import me.cortex.vulkanite.lib.cmd.VCommandPool; import me.cortex.vulkanite.lib.descriptors.DescriptorUpdateBuilder; +import me.cortex.vulkanite.lib.descriptors.VDescriptorSet; +import me.cortex.vulkanite.lib.memory.PoolLinearAllocator; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.memory.VGImage; import me.cortex.vulkanite.lib.memory.VImage; import me.cortex.vulkanite.lib.other.VImageView; import me.cortex.vulkanite.lib.other.VSampler; +import me.cortex.vulkanite.lib.other.VUtil; import me.cortex.vulkanite.lib.other.sync.VSemaphore; import me.cortex.vulkanite.lib.pipeline.RaytracePipelineBuilder; import me.cortex.vulkanite.lib.pipeline.VRaytracePipeline; import me.cortex.vulkanite.lib.shader.reflection.ShaderReflection; import me.cortex.vulkanite.mixin.iris.MixinCelestialUniforms; import me.cortex.vulkanite.mixin.iris.MixinCommonUniforms; -import net.coderbot.iris.gl.buffer.ShaderStorageBuffer; -import net.coderbot.iris.texture.pbr.PBRTextureHolder; -import net.coderbot.iris.texture.pbr.PBRTextureManager; -import net.coderbot.iris.uniforms.CapturedRenderingState; -import net.coderbot.iris.uniforms.CommonUniforms; -import net.coderbot.iris.uniforms.SystemTimeUniforms; +import net.irisshaders.iris.gl.buffer.ShaderStorageBuffer; +import net.irisshaders.iris.texture.pbr.PBRTextureHolder; +import net.irisshaders.iris.texture.pbr.PBRTextureManager; +import net.irisshaders.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.uniforms.CommonUniforms; +import net.irisshaders.iris.uniforms.SystemTimeUniforms; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.Camera; import net.minecraft.client.texture.AbstractTexture; @@ -46,17 +51,17 @@ import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; import static org.lwjgl.vulkan.KHRRayTracingPipeline.*; import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK12.VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; public class VulkanPipeline { private final VContext ctx; private final AccelerationManager accelerationManager; - private final VCommandPool singleUsePool; - private record RtPipeline(VRaytracePipeline pipeline, int commonSet, int geomSet, int customTexSet, int ssboSet) {} - private ArrayList raytracePipelines = new ArrayList<>(); + private record RtPipeline(VRef pipeline, int commonSet, int geomSet, int customTexSet, int ssboSet) {} + private final ArrayList raytracePipelines = new ArrayList<>(); - private final VSampler sampler; - private final VSampler ctexSampler; + private final VRef sampler; + private final VRef ctexSampler; private final SharedImageViewTracker[] irisRenderTargetViews; private final SharedImageViewTracker[] customTextureViews; @@ -64,77 +69,71 @@ private record RtPipeline(VRaytracePipeline pipeline, int commonSet, int geomSet private final SharedImageViewTracker blockAtlasNormalView; private final SharedImageViewTracker blockAtlasSpecularView; - private final VImage placeholderSpecular; - private final VImageView placeholderSpecularView; - private final VImage placeholderNormals; - private final VImageView placeholderNormalsView; - - private int fidx; + private final VRef placeholderSpecular; + private final VRef placeholderSpecularView; + private final VRef placeholderNormals; + private final VRef placeholderNormalsView; private final int maxIrisRenderTargets = 16; private final boolean supportsEntities; - public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, RaytracingShaderSet[] passes, int[] ssboIds, VGImage[] customTextures) { + private final PoolLinearAllocator uboAllocator; + + public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, RaytracingShaderSet[] passes, int[] ssboIds, List> customTextures) { this.ctx = ctx; this.accelerationManager = accelerationManager; - this.singleUsePool = ctx.cmd.createSingleUsePool(); { - this.customTextureViews = new SharedImageViewTracker[customTextures.length]; - for(int i = 0; i < customTextures.length; i++) { + this.customTextureViews = new SharedImageViewTracker[customTextures.size()]; + for (int i = 0; i < customTextures.size(); i++) { int index = i; - this.customTextureViews[i] = new SharedImageViewTracker(ctx, ()->customTextures[index]); + this.customTextureViews[i] = new SharedImageViewTracker(ctx, () -> new VRef<>(customTextures.get(index).get())); } this.irisRenderTargetViews = new SharedImageViewTracker[maxIrisRenderTargets]; - for(int i = 0; i < maxIrisRenderTargets; i++) { + for (int i = 0; i < maxIrisRenderTargets; i++) { this.irisRenderTargetViews[i] = new SharedImageViewTracker(ctx, null); } - this.blockAtlasView = new SharedImageViewTracker(ctx, ()->{ + this.blockAtlasView = new SharedImageViewTracker(ctx, () -> { AbstractTexture blockAtlas = MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")); - return ((IVGImage)blockAtlas).getVGImage(); + return ((IVGImage) blockAtlas).getVGImage(); }); - this.blockAtlasNormalView = new SharedImageViewTracker(ctx, ()->{ + this.blockAtlasNormalView = new SharedImageViewTracker(ctx, () -> { AbstractTexture blockAtlas = MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")); PBRTextureHolder holder = PBRTextureManager.INSTANCE.getOrLoadHolder(blockAtlas.getGlId());//((TextureAtlasExtension)blockAtlas).getPBRHolder() - return ((IVGImage)holder.getNormalTexture()).getVGImage(); + return ((IVGImage) holder.normalTexture()).getVGImage(); }); - this.blockAtlasSpecularView = new SharedImageViewTracker(ctx, ()->{ + this.blockAtlasSpecularView = new SharedImageViewTracker(ctx, () -> { AbstractTexture blockAtlas = MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier("minecraft", "textures/atlas/blocks.png")); PBRTextureHolder holder = PBRTextureManager.INSTANCE.getOrLoadHolder(blockAtlas.getGlId());//((TextureAtlasExtension)blockAtlas).getPBRHolder() - return ((IVGImage)holder.getSpecularTexture()).getVGImage(); + return ((IVGImage) holder.specularTexture()).getVGImage(); }); this.placeholderSpecular = ctx.memory.createImage2D(4, 4, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - this.placeholderSpecularView = new VImageView(ctx, placeholderSpecular); + this.placeholderSpecularView = VImageView.create(ctx, placeholderSpecular); this.placeholderNormals = ctx.memory.createImage2D(4, 4, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - this.placeholderNormalsView = new VImageView(ctx, placeholderNormals); + this.placeholderNormalsView = VImageView.create(ctx, placeholderNormals); try (var stack = stackPush()) { var initZeros = stack.callocInt(4 * 4); var initNormals = stack.mallocFloat(4 * 4 * 4); for (int i = 0; i < 4 * 4; i++) { - initNormals.put(new float[] {0.5f, 0.5f, 1.0f, 1.0f}); + initNormals.put(new float[]{0.5f, 0.5f, 1.0f, 1.0f}); } initNormals.rewind(); - var cmd = singleUsePool.createCommandBuffer(); - cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - cmd.encodeImageTransition(placeholderSpecular, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); - cmd.encodeImageTransition(placeholderNormals, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); - cmd.encodeImageUpload(ctx.memory, MemoryUtil.memAddress(initZeros), placeholderSpecular, initZeros.capacity() * 4, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - cmd.encodeImageUpload(ctx.memory, MemoryUtil.memAddress(initNormals), placeholderNormals, initNormals.capacity() * 4, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - cmd.encodeImageTransition(placeholderSpecular, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); - cmd.encodeImageTransition(placeholderNormals, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); - cmd.end(); - - ctx.cmd.submit(0, VkSubmitInfo.calloc(stack).sType$Default().pCommandBuffers(stack.pointers(cmd))); - - Vulkanite.INSTANCE.addSyncedCallback(cmd::enqueueFree); + ctx.cmd.executeWait(cmd -> { + cmd.encodeImageTransition(placeholderSpecular, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); + cmd.encodeImageTransition(placeholderNormals, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); + cmd.encodeImageUpload(ctx.memory, MemoryUtil.memAddress(initZeros), placeholderSpecular, initZeros.capacity() * 4L, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + cmd.encodeImageUpload(ctx.memory, MemoryUtil.memAddress(initNormals), placeholderNormals, initNormals.capacity() * 4L, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + cmd.encodeImageTransition(placeholderSpecular, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); + cmd.encodeImageTransition(placeholderNormals, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, 1); + }); } } - this.sampler = new VSampler(ctx, a->a.magFilter(VK_FILTER_NEAREST) + this.sampler = VSampler.create(ctx, a -> a.magFilter(VK_FILTER_NEAREST) .minFilter(VK_FILTER_NEAREST) .mipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) .addressModeU(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) @@ -145,7 +144,7 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray .borderColor(VK_BORDER_COLOR_INT_OPAQUE_BLACK) .maxAnisotropy(1.0f)); - this.ctexSampler = new VSampler(ctx, a->a.magFilter(VK_FILTER_LINEAR) + this.ctexSampler = VSampler.create(ctx, a -> a.magFilter(VK_FILTER_LINEAR) .minFilter(VK_FILTER_LINEAR) .mipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) .addressModeU(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) @@ -156,6 +155,10 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray .borderColor(VK_BORDER_COLOR_INT_OPAQUE_BLACK) .maxAnisotropy(1.0f)); + this.uboAllocator = new PoolLinearAllocator(ctx, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + 32 * 1024, + 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + if (passes == null) { supportsEntities = false; return; @@ -171,16 +174,16 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray supportsEntities = supportsEntitiesT; try { var commonSetExpected = new ShaderReflection.Set(new ShaderReflection.Binding[]{ - new ShaderReflection.Binding("", 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, false), - new ShaderReflection.Binding("", 1, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0, false), - new ShaderReflection.Binding("", 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, false), - new ShaderReflection.Binding("", 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, false), - new ShaderReflection.Binding("", 5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, false), - new ShaderReflection.Binding("", 6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, maxIrisRenderTargets, false), + new ShaderReflection.Binding("", 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, false), + new ShaderReflection.Binding("", 1, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0, false), + new ShaderReflection.Binding("", 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, false), + new ShaderReflection.Binding("", 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, false), + new ShaderReflection.Binding("", 5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, false), + new ShaderReflection.Binding("", 6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, maxIrisRenderTargets, false), }); var geomSetExpected = new ShaderReflection.Set(new ShaderReflection.Binding[]{ - new ShaderReflection.Binding("", 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, true) + new ShaderReflection.Binding("", 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, true) }); ArrayList customTexBindings = new ArrayList<>(); @@ -191,7 +194,7 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray ArrayList ssboBindings = new ArrayList<>(); for (int id : ssboIds) { - ssboBindings.add(new ShaderReflection.Binding("", id, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, true)); + ssboBindings.add(new ShaderReflection.Binding("", id, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, false)); } var ssboSetExpected = new ShaderReflection.Set(ssboBindings); @@ -206,8 +209,8 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray int customTexSet = -1; int ssboSet = -1; - for (int setIdx = 0; setIdx < pipe.reflection.getNSets(); setIdx++) { - var set = pipe.reflection.getSet(setIdx); + for (int setIdx = 0; setIdx < pipe.get().reflection.getNSets(); setIdx++) { + var set = pipe.get().reflection.getSet(setIdx); if (set.validate(commonSetExpected)) { commonSet = setIdx; } else if (set.validate(geomSetExpected)) { @@ -233,46 +236,62 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray } } - private VSemaphore previousSemaphore; - - private final EntityCapture capture = new EntityCapture(); - private void buildEntities() { + private void captureEntities() { accelerationManager.setEntityData(supportsEntities?capture.capture(CapturedRenderingState.INSTANCE.getTickDelta(), MinecraftClient.getInstance().world):null); } - public void renderPostShadows(List outImgs, Camera camera, ShaderStorageBuffer[] ssbos, MixinCelestialUniforms celestialUniforms) { - buildEntities(); + public void renderPostShadows(List> vgOutImgs, Camera camera, ShaderStorageBuffer[] ssbos, MixinCelestialUniforms celestialUniforms) { + var prof = MinecraftClient.getInstance().getProfiler(); + + for (int i = 0; i < 15; i++) { + if (VUtil._REPORT_GL_ERROR_()) { + break; + } else if (i == 14) { + System.err.println("Found OpenGL errors generated outside Vulkanite that can't be cleared"); + VUtil._CHECK_GL_ERROR_(); + } + } + + ctx.cmd.newFrame(); + VRegistry.INSTANCE.threadLocalCollect(); + prof.push("vulkanite_capture_entities"); + captureEntities(); + prof.pop(); - this.singleUsePool.doReleases(); PBRTextureManager.notifyPBRTexturesChanged(); var in = ctx.sync.createSharedBinarySemaphore(); - var outImgsGlIds = outImgs.stream().mapToInt(i -> i.glId).toArray(); - var outImgsGlLayouts = outImgs.stream().mapToInt(i -> GL_LAYOUT_GENERAL_EXT).toArray(); - in.glSignal(new int[0], outImgsGlIds, outImgsGlLayouts); - glFlush(); + var outImgsGlIds = vgOutImgs.stream().mapToInt(i -> i.get().glId).toArray(); + var outImgsGlLayouts = vgOutImgs.stream().mapToInt(i -> GL_LAYOUT_GENERAL_EXT).toArray(); + in.get().glSignal(new int[0], outImgsGlIds, outImgsGlLayouts); + // glFlush(); - var tlasLink = ctx.sync.createBinarySemaphore(); + var cmdRef = ctx.cmd.getSingleUsePool().createCommandBuffer(); + var cmd = cmdRef.get(); - var tlas = accelerationManager.buildTLAS(in, tlasLink); + prof.push("vulkanite_build_tlas"); + var tlas = accelerationManager.buildTLAS(0, cmd); + prof.pop(); if (tlas == null) { + VRegistry.INSTANCE.threadLocalCollect(); glFinish(); - tlasLink.free(); - in.free(); return; } + var outImgs = vgOutImgs.stream().map(i -> new VRef(i.get())).toList(); + var out = ctx.sync.createSharedBinarySemaphore(); - VBuffer uboBuffer; + + var vref_in = new VRef(in.get()); + var vref_out = new VRef(out.get()); + + var uboBuffer = uboAllocator.allocate(1024); { - uboBuffer = ctx.memory.createBuffer(1024, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); - long ptr = uboBuffer.map(); + prof.push("vulkanite_encode_rt_passes"); + long ptr = uboBuffer.buffer().get().map(); MemoryUtil.memSet(ptr, 0, 1024); { ByteBuffer bb = MemoryUtil.memByteBuffer(ptr, 1024); @@ -299,8 +318,8 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag bb.putInt(Float.BYTES * 41, flags); bb.rewind(); } - uboBuffer.unmap(); - uboBuffer.flush(); + uboBuffer.buffer().get().unmap(); + uboBuffer.buffer().get().flush(); // Call getView() on shared image view trackers to ensure they are created blockAtlasView.getView(); @@ -310,10 +329,6 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag v.getView(); } - //TODO: dont use a single use pool for commands like this... - var cmd = singleUsePool.createCommandBuffer(); - cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - { // Put barriers on images & transition to the optimal layout // These layouts also need to match the descriptor sets @@ -334,15 +349,18 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag for (var record : raytracePipelines) { var pipeline = record.pipeline; - pipeline.bind(cmd); - var layouts = pipeline.reflection.getLayouts(); // Should be cached already - var sets = new long[layouts.size()]; + cmd.bindRT(pipeline); + var layouts = pipeline.get().reflection.getLayouts(); // Should be cached already + var sets = new ArrayList>(layouts.size()); + for (int i = 0; i < layouts.size(); i++) { + sets.add(null); // Well, LOL, can't use Arrays.toList because it's generic + } if (record.commonSet != -1) { - var commonSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.commonSet)).allocateSet(); + var commonSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.commonSet)).get().allocateSet(); - var updater = new DescriptorUpdateBuilder(ctx, pipeline.reflection.getSet(record.commonSet)) - .set(commonSet.set) - .uniform(0, uboBuffer) + var updater = new DescriptorUpdateBuilder(ctx, pipeline.get().reflection.getSet(record.commonSet)) + .set(commonSet) + .uniform(0, uboBuffer.buffer(), uboBuffer.offset(), uboBuffer.size()) .acceleration(1, tlas) .imageSampler(3, blockAtlasView.getView(), sampler) .imageSampler(4, @@ -353,48 +371,46 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag blockAtlasSpecularView.getView() != null ? blockAtlasSpecularView.getView() : placeholderSpecularView, sampler); - List outImgViewList = new ArrayList<>(outImgs.size()); + List> outImgViewList = new ArrayList<>(outImgs.size()); for (int i = 0; i < outImgs.size(); i++) { int index = i; - outImgViewList.add(irisRenderTargetViews[i].getView(() -> outImgs.get(index))); + outImgViewList.add(irisRenderTargetViews[i].getView(() -> vgOutImgs.get(index))); } updater.imageStore(6, 0, outImgViewList); updater.apply(); - sets[record.commonSet] = commonSet.set; - cmd.addTransientResource(commonSet); + sets.set(record.commonSet, commonSet); } if (record.geomSet != -1) { - sets[record.geomSet] = accelerationManager.getGeometrySet(); + sets.set(record.geomSet, accelerationManager.getGeometrySet()); } if (record.customTexSet != -1) { - var ctexSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.customTexSet)).allocateSet(); + var ctexSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.customTexSet)).get().allocateSet(); - var updater = new DescriptorUpdateBuilder(ctx, pipeline.reflection.getSet(record.customTexSet)) - .set(ctexSet.set); + var updater = new DescriptorUpdateBuilder(ctx, pipeline.get().reflection.getSet(record.customTexSet)) + .set(ctexSet); for (int i = 0; i < customTextureViews.length; i++) { updater.imageSampler(i, customTextureViews[i].getView(), ctexSampler); } updater.apply(); - sets[record.customTexSet] = ctexSet.set; - cmd.addTransientResource(ctexSet); + sets.set(record.customTexSet, ctexSet); } if (record.ssboSet != -1) { - var ssboSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.ssboSet)).allocateSet(); + var ssboSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.ssboSet)).get().allocateSet(); - var updater = new DescriptorUpdateBuilder(ctx, pipeline.reflection.getSet(record.ssboSet)) - .set(ssboSet.set); + var updater = new DescriptorUpdateBuilder(ctx, pipeline.get().reflection.getSet(record.ssboSet)) + .set(ssboSet); for (ShaderStorageBuffer ssbo : ssbos) { - updater.buffer(ssbo.getIndex(), ((IVGBuffer) ssbo).getBuffer()); + updater.buffer(ssbo.getIndex(), new VRef<>(((IVGBuffer) ssbo).getBuffer().get())); } updater.apply(); - sets[record.ssboSet] = ssboSet.set; - cmd.addTransientResource(ssboSet); + sets.set(record.ssboSet, ssboSet); } - pipeline.bindDSet(cmd, sets); - pipeline.trace(cmd, outImgs.get(0).width, outImgs.get(0).height, 1); + cmd.bindDSet(sets); + cmd.traceRays(outImgs.get(0).get().width, outImgs.get(0).get().height, 1); + sets.forEach(VRef::close); // Barrier on the output images for (var img : outImgs) { @@ -416,83 +432,27 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag } } - cmd.end(); - var fence = ctx.sync.createFence(); - ctx.cmd.submit(0, new VCmdBuff[]{cmd}, new VSemaphore[]{tlasLink}, new int[]{VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR}, new VSemaphore[]{out}, fence); - - - var semCapture = previousSemaphore; - previousSemaphore = out; - ctx.sync.addCallback(fence, ()->{ - tlasLink.free(); - in.free(); - cmd.enqueueFree(); - fence.free(); - - uboBuffer.free(); - if (semCapture != null) { - semCapture.free(); - } - }); + prof.pop(); + ctx.cmd.submit(0, cmdRef, Arrays.asList(vref_in), Arrays.asList(vref_out), null); } - out.glWait(new int[0], outImgsGlIds, outImgsGlLayouts); - glFlush(); + cmdRef.close(); + tlas.close(); - fidx++; - fidx %= 10; + out.get().glWait(new int[0], outImgsGlIds, outImgsGlLayouts); + // glFlush(); + vref_in.close(); + vref_out.close(); + in.close(); + out.close(); + // System.out.println(VRegistry.INSTANCE.dumpStats()); } public void destory() { vkDeviceWaitIdle(ctx.device); - - // Check pending fences first - // Then destroy the cmd pool (which destroys linked transient resources) - ctx.sync.checkFences(); - if (singleUsePool != null) { - singleUsePool.doReleases(); - singleUsePool.free(); - } - if (previousSemaphore != null) { - previousSemaphore.free(); - } - // Finally destroy the pipelines - // (Which destroys the descriptor set layouts & releases the VTypedDescriptorPool) - for (var pass : raytracePipelines) { - if (pass != null) { - pass.pipeline.free(); - } - } - - for (SharedImageViewTracker customTexView : customTextureViews) { - if (customTexView != null) - customTexView.free(); - } - - for (SharedImageViewTracker irisRenderTargetView : irisRenderTargetViews) { - if (irisRenderTargetView != null) - irisRenderTargetView.free(); - } - - if (blockAtlasView != null) - blockAtlasView.free(); - if (blockAtlasNormalView != null) - blockAtlasNormalView.free(); - if (blockAtlasSpecularView != null) - blockAtlasSpecularView.free(); - if (placeholderNormalsView != null) - placeholderNormalsView.free(); - if (placeholderNormals != null) - placeholderNormals.free(); - if (placeholderSpecularView != null) - placeholderSpecularView.free(); - if (placeholderSpecular != null) - placeholderSpecular.free(); - if (sampler != null) - sampler.free(); - if (ctexSampler != null) - ctexSampler.free(); + ctx.cmd.newFrame(); + System.gc(); } diff --git a/src/main/java/me/cortex/vulkanite/compat/IRenderTargetVkGetter.java b/src/main/java/me/cortex/vulkanite/compat/IRenderTargetVkGetter.java index 7fce060..9b779cb 100644 --- a/src/main/java/me/cortex/vulkanite/compat/IRenderTargetVkGetter.java +++ b/src/main/java/me/cortex/vulkanite/compat/IRenderTargetVkGetter.java @@ -1,8 +1,9 @@ package me.cortex.vulkanite.compat; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; public interface IRenderTargetVkGetter { - VGImage getMain(); - VGImage getAlt(); + VRef getMain(); + VRef getAlt(); } diff --git a/src/main/java/me/cortex/vulkanite/compat/IVGBuffer.java b/src/main/java/me/cortex/vulkanite/compat/IVGBuffer.java index a9c6293..cd7e490 100644 --- a/src/main/java/me/cortex/vulkanite/compat/IVGBuffer.java +++ b/src/main/java/me/cortex/vulkanite/compat/IVGBuffer.java @@ -1,8 +1,9 @@ package me.cortex.vulkanite.compat; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGBuffer; public interface IVGBuffer { - VGBuffer getBuffer(); - void setBuffer(VGBuffer buffer); + VRef getBuffer(); + void setBuffer(VRef buffer); } diff --git a/src/main/java/me/cortex/vulkanite/compat/IVGImage.java b/src/main/java/me/cortex/vulkanite/compat/IVGImage.java index 00204ce..6487765 100644 --- a/src/main/java/me/cortex/vulkanite/compat/IVGImage.java +++ b/src/main/java/me/cortex/vulkanite/compat/IVGImage.java @@ -1,8 +1,9 @@ package me.cortex.vulkanite.compat; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; public interface IVGImage { - VGImage getVGImage(); - void setVGImage(VGImage image); + VRef getVGImage(); + void setVGImage(VRef image); } diff --git a/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSet.java b/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSet.java index e808b64..e6190b0 100644 --- a/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSet.java +++ b/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSet.java @@ -18,20 +18,14 @@ private record RayHit(ShaderModule close, ShaderModule any, ShaderModule interse private final ShaderModule[] raymiss; private final RayHit[] rayhits; - private final VShader[] allShader; - public RaytracingShaderSet(VContext ctx, RaytracingShaderSource source) { - List shaderList = new ArrayList<>(); - - VShader shader = VShader.compileLoad(ctx, source.raygen, VK_SHADER_STAGE_RAYGEN_BIT_KHR); - shaderList.add(shader); - this.raygen = shader.named(); + var shader = VShader.compileLoad(ctx, source.raygen, VK_SHADER_STAGE_RAYGEN_BIT_KHR); + this.raygen = shader.get().named(); this.raymiss = new ShaderModule[source.raymiss.length]; for (int i = 0; i < raymiss.length; i++) { shader = VShader.compileLoad(ctx, source.raymiss[i], VK_SHADER_STAGE_MISS_BIT_KHR); - shaderList.add(shader); - this.raymiss[i] = shader.named(); + this.raymiss[i] = shader.get().named(); } this.rayhits = new RayHit[source.rayhit.length]; @@ -41,27 +35,23 @@ public RaytracingShaderSet(VContext ctx, RaytracingShaderSource source) { ShaderModule close = null; if (hit.close() != null) { shader = VShader.compileLoad(ctx, hit.close(), VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - shaderList.add(shader); - close = shader.named(); + close = shader.get().named(); } ShaderModule any = null; if (hit.any() != null) { shader = VShader.compileLoad(ctx, hit.any(), VK_SHADER_STAGE_ANY_HIT_BIT_KHR); - shaderList.add(shader); - any = shader.named(); + any = shader.get().named(); } ShaderModule intersection = null; if (hit.intersection() != null) { shader = VShader.compileLoad(ctx, hit.intersection(), VK_SHADER_STAGE_INTERSECTION_BIT_KHR); - shaderList.add(shader); - intersection = shader.named(); + intersection = shader.get().named(); } this.rayhits[i] = new RayHit(close, any, intersection); } - this.allShader = shaderList.toArray(new VShader[0]); } public void apply(RaytracePipelineBuilder builder) { @@ -77,10 +67,4 @@ public void apply(RaytracePipelineBuilder builder) { public int getRayHitCount() { return rayhits.length; } - - public void delete() { - for (var shader : allShader) { - shader.free(); - } - } } diff --git a/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSource.java b/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSource.java index 1c50628..833c6d5 100644 --- a/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSource.java +++ b/src/main/java/me/cortex/vulkanite/compat/RaytracingShaderSource.java @@ -1,8 +1,5 @@ package me.cortex.vulkanite.compat; -import net.coderbot.iris.shaderpack.ProgramDirectives; -import net.coderbot.iris.shaderpack.ProgramSet; - public class RaytracingShaderSource { public record RayHitSource(String close, String any, String intersection) {} public final String name; diff --git a/src/main/java/me/cortex/vulkanite/lib/base/TrackedResourceObject.java b/src/main/java/me/cortex/vulkanite/lib/base/TrackedResourceObject.java deleted file mode 100644 index 40f9921..0000000 --- a/src/main/java/me/cortex/vulkanite/lib/base/TrackedResourceObject.java +++ /dev/null @@ -1,38 +0,0 @@ -package me.cortex.vulkanite.lib.base; - -import java.lang.ref.Cleaner; - -public abstract class TrackedResourceObject { - - private final Ref ref; - public TrackedResourceObject() { - this.ref = register(this); - } - - protected void free0() { - ref.freedRef[0] = true; - ref.cleanable.clean(); - } - - public abstract void free(); - - public boolean isFreed() { - return ref.freedRef[0]; - } - - private record Ref(Cleaner.Cleanable cleanable, boolean[] freedRef) {} - - private static final Cleaner cleaner = Cleaner.create(); - public static Ref register(Object obj) { - String clazz = obj.getClass().getName(); - Throwable trace = new Throwable(); - boolean[] freed = new boolean[1]; - var clean = cleaner.register(obj, ()->{ - if (!freed[0]) { - System.err.println("Object named: "+ clazz+" was not freed, location at: "); - trace.printStackTrace(); - } - }); - return new Ref(clean, freed); - } -} diff --git a/src/main/java/me/cortex/vulkanite/lib/base/VContext.java b/src/main/java/me/cortex/vulkanite/lib/base/VContext.java index 2dcdfd3..790d897 100644 --- a/src/main/java/me/cortex/vulkanite/lib/base/VContext.java +++ b/src/main/java/me/cortex/vulkanite/lib/base/VContext.java @@ -3,8 +3,14 @@ import me.cortex.vulkanite.lib.cmd.CommandManager; import me.cortex.vulkanite.lib.other.sync.SyncManager; import me.cortex.vulkanite.lib.memory.MemoryManager; +import org.lwjgl.vulkan.VkDebugUtilsObjectNameInfoEXT; import org.lwjgl.vulkan.VkDevice; +import static org.lwjgl.system.MemoryStack.stackPush; +import static org.lwjgl.system.MemoryUtil.memUTF8; +import static org.lwjgl.vulkan.EXTDebugUtils.vkSetDebugUtilsObjectNameEXT; +import static org.lwjgl.vulkan.VK10.VK_OBJECT_TYPE_UNKNOWN; + public class VContext { public final VkDevice device; @@ -13,11 +19,25 @@ public class VContext { public final SyncManager sync; public final CommandManager cmd; public final DeviceProperties properties; - public VContext(VkDevice device, int queueCount, boolean hasDeviceAddresses) { + public final boolean hasDebugUtils; + public VContext(VkDevice device, int queueCount, boolean hasDeviceAddresses, boolean hasDebugUtils) { this.device = device; memory = new MemoryManager(device, hasDeviceAddresses); sync = new SyncManager(device); cmd = new CommandManager(device, queueCount); properties = new DeviceProperties(device); + this.hasDebugUtils = hasDebugUtils; + } + + public void setDebugUtilsObjectName(long handle, int objectType, String name) { + if (hasDebugUtils) { + try (var stack = stackPush()) { + vkSetDebugUtilsObjectNameEXT(device, VkDebugUtilsObjectNameInfoEXT.calloc(stack) + .sType$Default() + .objectType(objectType) + .objectHandle(handle) + .pObjectName(memUTF8(name))); + } + } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/base/VObject.java b/src/main/java/me/cortex/vulkanite/lib/base/VObject.java new file mode 100644 index 0000000..832e933 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/base/VObject.java @@ -0,0 +1,24 @@ +package me.cortex.vulkanite.lib.base; + +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class VObject { + protected final AtomicInteger refCount = new AtomicInteger(0); + protected Object heap = null; + + protected abstract void free(); + + protected void incRef() { + if (refCount.incrementAndGet() == 1) { + // First reference, put into registry + // So that the object is kept alive until we finish running `free()` + VRegistry.INSTANCE.register(this); + } + } + + protected void decRef() { + if (refCount.decrementAndGet() == 0) { + VRegistry.INSTANCE.unregister(this); + } + } +} diff --git a/src/main/java/me/cortex/vulkanite/lib/base/VRef.java b/src/main/java/me/cortex/vulkanite/lib/base/VRef.java new file mode 100644 index 0000000..74a8b59 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/base/VRef.java @@ -0,0 +1,69 @@ +package me.cortex.vulkanite.lib.base; + +import org.jetbrains.annotations.NotNull; + +import java.io.Closeable; +import java.lang.ref.Cleaner; +import java.lang.ref.WeakReference; + +public class VRef implements Closeable { + private static final Cleaner cleaner = Cleaner.create(); + private final State state; + private final Cleaner.Cleanable cleanable; + + public VRef(T ref) { + if (ref == null) { + throw new NullPointerException("VRef to null object"); + } + ref.incRef(); + + state = new State<>(ref); + cleanable = cleaner.register(this, state); + } + + /** + * (Optional) Decrement the reference count and release the object if the reference count reaches 0. + * This method can be called multiple times, but the object will only be released once. + * If this method is not called, the object will be released when the VRef is garbage collected. + */ + @Override + public void close() { + cleanable.clean(); + } + + @NotNull + public VRef addRef() { + return new VRef<>(state.get()); + } + + @NotNull + public VRef addRefGeneric() { + return new VRef<>(state.get()); + } + + @NotNull + public T get() { + return state.get(); + } + + static class State extends WeakReference implements Runnable { + State(T ref) { + super(ref); + } + + @NotNull + @Override + public T get() { + T ref = super.get(); + if (ref == null) { + throw new NullPointerException("Referenced object has been garbage collected while VRef was still active"); + } + return ref; + } + + @Override + public void run() { + get().decRef(); + } + } +} diff --git a/src/main/java/me/cortex/vulkanite/lib/base/VRegistry.java b/src/main/java/me/cortex/vulkanite/lib/base/VRegistry.java new file mode 100644 index 0000000..cb623b1 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/base/VRegistry.java @@ -0,0 +1,117 @@ +package me.cortex.vulkanite.lib.base; + +import com.google.common.collect.ConcurrentHashMultiset; +import java.util.concurrent.ConcurrentLinkedDeque; +import me.cortex.vulkanite.lib.memory.VBuffer; + +import java.util.*; + +import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; +import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; +import static org.lwjgl.vulkan.KHRRayTracingPipeline.VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK12.VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + +public class VRegistry { + public static final VRegistry INSTANCE = new VRegistry(); + + private static class ObjectHeap { + protected final long threadId = Thread.currentThread().getId(); + protected final String threadName = Thread.currentThread().getName(); + + protected final HashSet objects = new HashSet<>(); + protected final ConcurrentLinkedDeque toFree = new ConcurrentLinkedDeque<>(); + + protected void collect() { + if (Thread.currentThread().getId() != threadId) { + throw new IllegalStateException("Object heap collect called from wrong thread"); + } + VObject object; + while ((object = toFree.poll()) != null) { + objects.remove(object); + object.free(); + } + } + } + + private final ConcurrentHashMultiset objectHeaps = ConcurrentHashMultiset.create(); + + private final ThreadLocal heap = ThreadLocal.withInitial(()->{ + var heap = new ObjectHeap(); + objectHeaps.add(heap); + return heap; + }); + + private VRegistry() { + } + + public void register(VObject object) { + heap.get().objects.add(object); + object.heap = heap.get(); + } + + public void unregister(VObject object) { + ObjectHeap heap = (ObjectHeap) object.heap; + heap.toFree.add(object); + } + + private static final HashMap usageNames = new HashMap<>() {{ + put(VK_BUFFER_USAGE_TRANSFER_DST_BIT, "TRANSFER_DST"); + put(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "TRANSFER_SRC"); + put(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, "UNIFORM_BUFFER"); + put(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, "STORAGE_BUFFER"); + put(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, "INDEX_BUFFER"); + put(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, "VERTEX_BUFFER"); + put(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, "SHADER_DEVICE_ADDRESS"); + put(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, "ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY"); + put(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR, "ACCELERATION_STRUCTURE_STORAGE"); + put(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, "SHADER_BINDING_TABLE"); + }}; + + public String dumpStats() { + final StringBuilder sb = new StringBuilder(); + + ObjectHeap heap = this.heap.get(); + var objects = heap.objects; + + sb.append("\nVRegistry (Thread=").append(heap.threadId).append(" ").append(heap.threadName).append("): "); + sb.append(objects.size()).append(" objects\n"); + sb.append("Objects:\n"); + + Map typeCount = new TreeMap<>(); + for (VObject object : objects) { + var key = object.getClass().getTypeName(); + typeCount.put(key, typeCount.getOrDefault(key, 0) + 1); + } + + for (String type : typeCount.keySet()) { + sb.append(" ").append(type).append(": ").append(typeCount.get(type)).append("\n"); + } + + Map bufferUsage = new TreeMap<>(); + for (VObject object : objects) { + if (object instanceof VBuffer buffer) { + var usage = buffer.usage(); + bufferUsage.put(usage, bufferUsage.getOrDefault(usage, 0) + 1); + } + } + + sb.append("Buffer Count Per Usage:\n"); + for (int usage : bufferUsage.keySet()) { + sb.append(" ").append(usage).append(": ").append(bufferUsage.get(usage)).append("\n"); + sb.append(" ("); + usageNames.forEach((key, value) -> { + if ((usage & key) != 0) { + sb.append(value).append(", "); + } + }); + sb.append(")\n"); + } + + return sb.toString(); + } + + public void threadLocalCollect() { + heap.get().collect(); + } +} diff --git a/src/main/java/me/cortex/vulkanite/lib/base/initalizer/VInitializer.java b/src/main/java/me/cortex/vulkanite/lib/base/initalizer/VInitializer.java index 75a9e6a..715eb83 100644 --- a/src/main/java/me/cortex/vulkanite/lib/base/initalizer/VInitializer.java +++ b/src/main/java/me/cortex/vulkanite/lib/base/initalizer/VInitializer.java @@ -18,6 +18,7 @@ import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.system.MemoryUtil.memUTF8; +import static org.lwjgl.vulkan.EXTDebugUtils.*; import static org.lwjgl.vulkan.VK10.*; import static org.lwjgl.vulkan.VK11.*; @@ -26,6 +27,7 @@ public class VInitializer { private VkPhysicalDevice physicalDevice; private VkDevice device; private int queueCount; + private long debugMessenger = 0; public VInitializer(String appName, String engineName, int major, int minor, String[] extensions, String[] layers) { try (MemoryStack stack = stackPush()) { VkApplicationInfo appInfo = VkApplicationInfo.calloc(stack) @@ -44,6 +46,24 @@ public VInitializer(String appName, String engineName, int major, int minor, Str _CHECK_(vkCreateInstance(instanceCreateInfo, null, result)); instance = new VkInstance(result.get(0), instanceCreateInfo); + + if (Arrays.asList(extensions).contains(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = VkDebugUtilsMessengerCreateInfoEXT.calloc(stack) + .sType$Default() + .messageSeverity(VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + .messageType(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + .pfnUserCallback((messageSeverity, messageTypes, pCallbackData, pUserData) -> { + VkDebugUtilsMessengerCallbackDataEXT callbackData = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData); + System.err.println("Validation layer: " + callbackData.pMessageString()); + Thread.dumpStack(); + return VK_FALSE; + }); + + var pDebugMessenger = stack.mallocLong(1); + _CHECK_(vkCreateDebugUtilsMessengerEXT(instance, debugCreateInfo, null, pDebugMessenger)); + debugMessenger = pDebugMessenger.get(0); + // Runtime.getRuntime().addShutdownHook(new Thread(() -> vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, null))); + } } } @@ -61,7 +81,7 @@ public void findPhysicalDevice() { } //TODO: add nice queue creation system - public void createDevice(List extensions, List layers, float[] queuePriorities, Consumer deviceFeatures, List> applicators) { + public void createDevice(List extensions, List layers, float[] queuePriorities, Consumer deviceFeatures, List> applicators, List> postApplicators) { var deviceExtensions = new HashSet<>(getDeviceExtensionStrings(physicalDevice)); for (var extension : extensions) { if (!deviceExtensions.contains(extension)) { @@ -93,10 +113,15 @@ public void createDevice(List extensions, List layers, float[] q long chain = createInfo.address(); var deviceProperties2 = VkPhysicalDeviceFeatures2.calloc(stack).sType$Default(); - for (var applicator : applicators) { + if (postApplicators.size() != applicators.size()) { + throw new IllegalStateException("Post applicators and applicators must be the same size"); + } + for (int i = 0; i < applicators.size(); i++) { + var applicator = applicators.get(i); Struct feature = applicator.apply(stack); deviceProperties2.pNext(feature.address()); vkGetPhysicalDeviceFeatures2(physicalDevice, deviceProperties2); + postApplicators.get(i).accept(feature); long next = feature.address(); MemoryUtil.memPutAddress(chain+8, next); chain = next; @@ -165,6 +190,6 @@ private VkExtensionProperties.Buffer getDeviceExtensions(MemoryStack stack, VkPh public VContext createContext() { //TODO:FIXME: DONT HARDCODE THE FACT IT HAS DEVICE ADDRESSES - return new VContext(device, queueCount, true); + return new VContext(device, queueCount, true, debugMessenger != 0); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/cmd/CommandManager.java b/src/main/java/me/cortex/vulkanite/lib/cmd/CommandManager.java index 794cab0..724c7d2 100644 --- a/src/main/java/me/cortex/vulkanite/lib/cmd/CommandManager.java +++ b/src/main/java/me/cortex/vulkanite/lib/cmd/CommandManager.java @@ -1,100 +1,323 @@ package me.cortex.vulkanite.lib.cmd; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; import com.mojang.blaze3d.systems.RenderSystem; - import io.netty.util.internal.shaded.org.jctools.queues.MessagePassingQueue.Consumer; +import it.unimi.dsi.fastutil.ints.Int2LongArrayMap; +import it.unimi.dsi.fastutil.ints.Int2LongMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectSortedMap; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.other.sync.VFence; import me.cortex.vulkanite.lib.other.sync.VSemaphore; -import org.lwjgl.vulkan.VkCommandBufferBeginInfo; -import org.lwjgl.vulkan.VkDevice; -import org.lwjgl.vulkan.VkQueue; -import org.lwjgl.vulkan.VkSubmitInfo; +import org.lwjgl.vulkan.*; +import java.nio.IntBuffer; import java.nio.LongBuffer; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; +import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK12.vkGetSemaphoreCounterValue; +import static org.lwjgl.vulkan.VK12.vkWaitSemaphores; //Manages multiple command queues and fence synchronizations public class CommandManager { private final VkDevice device; - private final VkQueue[] queues; - - private final VCommandPool singleUsePool; + private final Queue[] queues; + private final ThreadLocal> threadLocalPool = + ThreadLocal.withInitial(() -> { + var pool = createSingleUsePool(); + pool.get().setDebugUtilsObjectName("Thread-local single use pool"); + return pool; + }); public CommandManager(VkDevice device, int queues) { this.device = device; - this.queues = new VkQueue[queues]; - try (var stack = stackPush()) { - var pQ = stack.pointers(0); - for (int i = 0; i < queues; i++) { - vkGetDeviceQueue(device, 0, i, pQ); - System.out.println("Queue "+i+" has address " + Long.toHexString(pQ.get(0))); - this.queues[i] = new VkQueue(pQ.get(0), device); - } + this.queues = new Queue[queues]; + for (int i = 0; i < queues; i++) { + this.queues[i] = new Queue(i, device); } - this.singleUsePool = createSingleUsePool(); } - public VCommandPool createSingleUsePool() { + public VRef createSingleUsePool() { return createPool(VK_COMMAND_POOL_CREATE_TRANSIENT_BIT); } - public VCommandPool createPool(int flags) { - return new VCommandPool(device, flags); + public VRef createPool(int flags) { + return new VRef<>(new VCommandPool(device, flags)); } - public void submit(int queueId, VkSubmitInfo submit) { - try (var stack = stackPush()) { - vkQueueSubmit(queues[queueId], submit, 0); - } + public VCommandPool getSingleUsePool() { + return threadLocalPool.get().get(); } - public void submitOnceAndWait(int queueId, VCmdBuff cmdBuff) { - try (var stack = stackPush()) { - var submit = VkSubmitInfo.calloc(stack).sType$Default() - .pCommandBuffers(stack.pointers(cmdBuff)) - .pWaitSemaphores(stack.longs()) - .pWaitDstStageMask(stack.ints()) - .pSignalSemaphores(stack.longs()); - vkQueueSubmit(queues[queueId], submit, 0); - vkQueueWaitIdle(queues[queueId]); - cmdBuff.freeInternal(); - } + public void submitOnceAndWait(int queueId, final VRef cmdBuff) { + long exec = this.submit(queueId, cmdBuff); + this.hostWaitForExecution(queueId, exec); + cmdBuff.close(); } public void executeWait(Consumer cmdbuf) { - var cmd = singleUsePool.createCommandBuffer(); - cmd.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - cmdbuf.accept(cmd); - cmd.end(); + var cmd = getSingleUsePool().createCommandBuffer(); + cmdbuf.accept(cmd.get()); submitOnceAndWait(0, cmd); } - //TODO: if its a single use command buffer, automatically add the required fences and stuff to free the command buffer once its done - public void submit(int queueId, VCmdBuff[] cmdBuffs, VSemaphore[] waits, int[] waitStages, VSemaphore[] triggers, VFence fence) { + /** + * Enqueues a wait for a timeline value on a queue + * + * @param waitQueueId The queue that will wait + * @param executionQueueId The queue whose timeline value will be waited for + * @param execution The timeline value to wait for + */ + public void queueWaitForExeuction(int waitQueueId, int executionQueueId, long execution) { + queues[waitQueueId].waitForExecution(executionQueueId, execution); + } + + /** + * Enqueues a wait for a timeline value on a queue + * + * @param waitQueueId The queue that will wait + * @param executionQueueId The queue whose timeline value will be waited for + * @param executions The timeline values to wait for + */ + public void queueWaitForExecutions(int waitQueueId, int executionQueueId, List executions) { + queues[waitQueueId].waitForExecutions(executionQueueId, executions); + } + + /** + * Wait on the host for a timeline value on a queue + * + * @param waitQueueId The queue whose timeline value will be waited for + * @param execution The timeline value to wait for + */ + public void hostWaitForExecution(int waitQueueId, long execution) { + var waitQueue = queues[waitQueueId]; + + try (var stack = stackPush()) { + VkSemaphoreWaitInfo waitInfo = VkSemaphoreWaitInfo.calloc(stack) + .sType$Default() + .pSemaphores(stack.longs(waitQueue.timelineSema.get().address())) + .semaphoreCount(1) + .pValues(stack.longs(execution)); + + _CHECK_(vkWaitSemaphores(device, waitInfo, -1)); + } + + waitQueue.updateCompletedTimestamp(execution); + waitQueue.collect(); + } + + public long getQueueCurrentExecution(int queueId) { + return queues[queueId].getCurrentExecution(); + } + + public long submit(int queueId, final VRef cmdBuff) { + return submit(queueId, cmdBuff, null, null, null); + } + + public long submit(int queueId, final VRef cmdBuff, List> waits, List> triggers, VFence fence) { if (queueId == 0) { RenderSystem.assertOnRenderThread(); } + return queues[queueId].submit(cmdBuff, queues, waits, triggers, fence); + } - try (var stack = stackPush()) { - LongBuffer waitSemaphores = stack.mallocLong(waits.length); - LongBuffer signalSemaphores = stack.mallocLong(triggers.length); - for (var wait : waits) {waitSemaphores.put(wait.address());} - for (var trigger : triggers) {signalSemaphores.put(trigger.address());} - waitSemaphores.rewind(); - signalSemaphores.rewind(); - var submit = VkSubmitInfo.calloc(stack).sType$Default() - .pCommandBuffers(stack.pointers(cmdBuffs)) - .pWaitSemaphores(waitSemaphores) - .waitSemaphoreCount(waits.length) - .pWaitDstStageMask(stack.ints(waitStages)) - .pSignalSemaphores(signalSemaphores); - vkQueueSubmit(queues[queueId], submit, fence==null?0:fence.address()); + public void waitQueueIdle(int queue) { + queues[queue].waitIdle(); + queues[queue].collect(); + } + + public void newFrame() { + for (var queue : queues) { + queue.newFrame(); } } - public void waitQueueIdle(int queue) { - vkQueueWaitIdle(queues[queue]); + private static class Queue { + private record Submission(long t, VRef ref) {} + + public final VkQueue queue; + private final Int2LongArrayMap waitingFor = new Int2LongArrayMap(); + private final List submitted = new ArrayList<>(); + public final VRef timelineSema; +// public final Deque frameTimestamps = new ArrayDeque<>(3); + public AtomicLong timeline = new AtomicLong(1); + public AtomicLong completedTimestamp = new AtomicLong(0); + + public Queue(int queueId, VkDevice device) { + try (var stack = stackPush()) { + var pQ = stack.pointers(0); + vkGetDeviceQueue(device, 0, queueId, pQ); + + this.queue = new VkQueue(pQ.get(0), device); + + var timelineCreateInfo = VkSemaphoreTypeCreateInfo.calloc(stack) + .sType$Default() + .semaphoreType(VK12.VK_SEMAPHORE_TYPE_TIMELINE) + .initialValue(0); + + var semaphoreCreateInfo = VkSemaphoreCreateInfo.calloc(stack) + .sType$Default() + .pNext(timelineCreateInfo.address()); + + var pSemaphore = stack.longs(0); + vkCreateSemaphore(device, semaphoreCreateInfo, null, pSemaphore); + this.timelineSema = VSemaphore.create(device, pSemaphore.get(0)); + } + } + + public void updateCompletedTimestamp(long newTimestamp) { + // completedTimestamp.atomicMax(newTimestamp); + long current; + do { + current = completedTimestamp.get(); + } while (current < newTimestamp && !completedTimestamp.compareAndSet(current, newTimestamp)); + } + + public void newFrame() { +// if (frameTimestamps.size() >= 3) { +// long oldest = frameTimestamps.removeFirst(); +// completedTimestamp = Long.max(completedTimestamp, oldest); +// } +// frameTimestamps.addLast(completedTimestamp); + + updateCompletedTimestamp(getCurrentExecution()); + collect(); + } + + public void collect() { + synchronized (submitted) { + long completedTimestamp = this.completedTimestamp.get(); + + submitted.removeIf((rec) -> { + if (rec.t <= completedTimestamp) { + rec.ref.close(); + return true; + } + return false; + }); + } + } + + public void waitIdle() { + synchronized (waitingFor) { + vkQueueWaitIdle(queue); + waitingFor.clear(); + } + + updateCompletedTimestamp(getCurrentExecution()); + collect(); + } + + public void waitForExecution(int execQueue, long execution) { + synchronized (waitingFor) { + waitingFor.put(execQueue, Long.max(waitingFor.getOrDefault(execQueue, 0), execution)); + } + } + + public void waitForExecutions(int execQueue, List executions) { + synchronized (waitingFor) { + long execMax = executions.stream().mapToLong(Long::longValue).max().orElse(waitingFor.getOrDefault(execQueue, 0)); + waitingFor.put(execQueue, execMax); + } + } + + public long submit(final VRef cmdBuff, Queue[] queues, List> waits, List> triggers, VFence fence) { + long t = timeline.getAndIncrement(); + + synchronized (waitingFor) { + // We need to hold the lock until we have submitted cmdbuf into the queue + // Otherwise it might be possible that another thread will submit a cmdbuf without waiting for anything + // Queue submits has strong API ordering + var timelineWaitingEntries = waitingFor.int2LongEntrySet(); + waitingFor.clear(); + + try (var stack = stackPush()) { + + int waitCount = (waits == null ? 0 : waits.size()) + timelineWaitingEntries.size(); + int triggerCount = (triggers == null ? 0 : triggers.size()) + 1; + + LongBuffer waitSemaphores = stack.mallocLong(waitCount); + LongBuffer signalSemaphores = stack.mallocLong(triggerCount); + LongBuffer waitTimelineValues = stack.mallocLong(waitCount); + LongBuffer signalTimelineValues = stack.mallocLong(triggerCount); + IntBuffer waitStages = stack.mallocInt(waitCount); + // Traditional binary semaphores + if (waits != null) { + for (var wait : waits) { + waitSemaphores.put(wait.get().address()); + waitTimelineValues.put(0); + waitStages.put(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + cmdBuff.get().addSemaphoreRef(wait); + } + } + if (triggers != null) { + for (var trigger : triggers) { + signalSemaphores.put(trigger.get().address()); + signalTimelineValues.put(0); + cmdBuff.get().addSemaphoreRef(trigger); + } + } + // Timeline semaphores + for (var entry : timelineWaitingEntries) { + if (entry.getLongValue() == 0) { + continue; + } + var sema = queues[entry.getIntKey()].timelineSema; + waitSemaphores.put(sema.get().address()); + waitTimelineValues.put(entry.getLongValue()); + waitStages.put(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + cmdBuff.get().addSemaphoreRef(sema); + } + signalSemaphores.put(timelineSema.get().address()); + signalTimelineValues.put(t); + cmdBuff.get().addSemaphoreRef(timelineSema); + + waitSemaphores.rewind(); + signalSemaphores.rewind(); + waitTimelineValues.rewind(); + signalTimelineValues.rewind(); + waitStages.rewind(); + + var timelineSubmitInfo = VkTimelineSemaphoreSubmitInfo.calloc(stack) + .sType$Default() + .pWaitSemaphoreValues(waitTimelineValues) + .waitSemaphoreValueCount(waitCount) + .pSignalSemaphoreValues(signalTimelineValues) + .signalSemaphoreValueCount(triggerCount); + + var submit = VkSubmitInfo.calloc(stack).sType$Default() + .pCommandBuffers(stack.pointers(cmdBuff.get().seal())) + .pWaitSemaphores(waitSemaphores) + .waitSemaphoreCount(waitCount) + .pWaitDstStageMask(waitStages) + .pSignalSemaphores(signalSemaphores) + .pNext(timelineSubmitInfo.address()); + _CHECK_(vkQueueSubmit(queue, submit, fence == null ? 0 : fence.address())); + } + } + + synchronized (submitted) { + submitted.add(new Submission(t, cmdBuff.addRef())); + } + + return t; + } + + public long getCurrentExecution() { + try (var stack = stackPush()) { + var lp = stack.longs(0); + vkGetSemaphoreCounterValue(queue.getDevice(), timelineSema.get().address(), lp); + return lp.get(0); + } + } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java b/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java index bf61272..c5b7ecf 100644 --- a/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java +++ b/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java @@ -1,97 +1,206 @@ package me.cortex.vulkanite.lib.cmd; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; +import me.cortex.vulkanite.lib.descriptors.VDescriptorSet; import me.cortex.vulkanite.lib.memory.MemoryManager; +import me.cortex.vulkanite.lib.memory.VAccelerationStructure; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.memory.VImage; -import org.lwjgl.system.Pointer; -import org.lwjgl.vulkan.VK; -import org.lwjgl.vulkan.VkBufferCopy; -import org.lwjgl.vulkan.VkBufferImageCopy; -import org.lwjgl.vulkan.VkBufferMemoryBarrier; -import org.lwjgl.vulkan.VkCommandBuffer; -import org.lwjgl.vulkan.VkCommandBufferBeginInfo; -import org.lwjgl.vulkan.VkDevice; -import org.lwjgl.vulkan.VkImageMemoryBarrier; -import org.lwjgl.vulkan.VkMemoryBarrier; +import me.cortex.vulkanite.lib.other.VQueryPool; +import me.cortex.vulkanite.lib.other.sync.VGSemaphore; +import me.cortex.vulkanite.lib.other.sync.VSemaphore; +import me.cortex.vulkanite.lib.pipeline.VComputePipeline; +import me.cortex.vulkanite.lib.pipeline.VRaytracePipeline; +import org.lwjgl.vulkan.*; import org.lwjgl.system.MemoryUtil; import static org.lwjgl.util.vma.Vma.VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; import static org.lwjgl.system.MemoryStack.stackPush; +import static org.lwjgl.vulkan.KHRRayTracingPipeline.*; +import static org.lwjgl.vulkan.KHRRayTracingPipeline.VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; import static org.lwjgl.vulkan.VK10.*; -import static org.lwjgl.vulkan.KHRRayTracingPipeline.VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; +import java.util.*; //TODO: Track with TrackedResourceObject but need to be careful due to how the freeing works -public class VCmdBuff extends TrackedResourceObject implements Pointer { - private final VCommandPool pool; - public final VkCommandBuffer buffer; +public class VCmdBuff extends VObject { + private final VRef pool; + private VkCommandBuffer buffer; - private HashSet transientResources; + @SuppressWarnings("FieldCanBeLocal") + private final List> refs = new ArrayList<>(); - VCmdBuff(VCommandPool pool, VkCommandBuffer buff) { - this.pool = pool; - this.buffer = buff; - this.transientResources = new HashSet<>(); + public void addBufferRef(final VRef buffer) { + refs.add(buffer.addRefGeneric()); + } + + // This is a generic method that can be used to add any type of VObject to the refs list + // ref should be produced by addRefGeneric() method of the object + public void moveRefGeneric(final VRef ref) { + refs.add(ref); } - //Enqueues the pool to be freed by the owning thread - public void enqueueFree() { - pool.free(this); + public void addImageRef(final VRef image) { + refs.add(image.addRefGeneric()); + } + public void addSemaphoreRef(final VRef semaphore) { + refs.add(semaphore.addRefGeneric()); + } + public void addVGSemaphoreRef(final VRef semaphore) { + refs.add(semaphore.addRefGeneric()); + } + public void addAccelerationStructureRef(final VRef accelerationStructure) { + refs.add(accelerationStructure.addRefGeneric()); } - public void begin(int flags) { + protected VCmdBuff(VRef pool, VkCommandBuffer buff, int flags) { + this.pool = pool; + this.buffer = buff; + try (var stack = stackPush()) { vkBeginCommandBuffer(buffer, VkCommandBufferBeginInfo.calloc(stack).sType$Default().flags(flags)); } } - public void end() { - vkEndCommandBuffer(buffer); + public final VkCommandBuffer buffer() { + return buffer; + } + + private VkCommandBuffer finalizedBuffer = null; + + public VkCommandBuffer seal() { + if (finalizedBuffer != null) { + return finalizedBuffer; + } + finalizedBuffer = buffer; + buffer = null; + vkEndCommandBuffer(finalizedBuffer); + return finalizedBuffer; + } + + private long currentPipelineLayout = -1; + private int currentShaderStageMask = 0; + private int currentPipelineBindPoint = -1; + + private VkStridedDeviceAddressRegionKHR gen, miss, hit, callable; + + public void bindCompute(final VRef pipeline) { + vkCmdBindPipeline(buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get().pipeline()); + refs.add(new VRef<>(pipeline.get())); + currentPipelineLayout = pipeline.get().layout(); + currentShaderStageMask = VK_SHADER_STAGE_COMPUTE_BIT; + currentPipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + } + + public void bindRT(final VRef pipeline) { + vkCmdBindPipeline(buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get().pipeline); + refs.add(new VRef<>(pipeline.get())); + currentPipelineLayout = pipeline.get().layout; + currentShaderStageMask = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR; + currentPipelineBindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; + + gen = pipeline.get().gen; + miss = pipeline.get().miss; + hit = pipeline.get().hit; + callable = pipeline.get().callable; + } + + public void traceRays(int width, int height, int depth) { + vkCmdTraceRaysKHR(buffer, gen, miss, hit, callable, width, height, depth); + } + + public void bindDSet(VRef... sets) { + long[] vkSets = Arrays.stream(sets).mapToLong(s -> s.get().set).toArray(); + vkCmdBindDescriptorSets(buffer, currentPipelineBindPoint, currentPipelineLayout, 0, vkSets, null); + refs.addAll(Arrays.stream(sets).map(s -> new VRef(s.get())).toList()); + } + + public void bindDSet(List> sets) { + long[] vkSets = sets.stream().mapToLong(s -> s.get().set).toArray(); + vkCmdBindDescriptorSets(buffer, currentPipelineBindPoint, currentPipelineLayout, 0, vkSets, null); + refs.addAll(sets.stream().map(s -> new VRef(s.get())).toList()); + } + + public void pushConstants(int offset, int size, long dataPtr) { + nvkCmdPushConstants(buffer, currentPipelineLayout, VK_SHADER_STAGE_ALL, offset, size, dataPtr); + } + + public void pushConstants(int offset, long[] data) { + vkCmdPushConstants(buffer, currentPipelineLayout, VK_SHADER_STAGE_ALL, offset, data); + } + + public void dispatch(int x, int y, int z) { + if (currentShaderStageMask != VK_SHADER_STAGE_COMPUTE_BIT || currentPipelineLayout == -1) { + throw new IllegalStateException("No compute pipeline bound"); + } + vkCmdDispatch(buffer, x, y, z); + } + + public void resetQueryPool(final VRef queryPool, int first, int size) { + vkCmdResetQueryPool(buffer, queryPool.get().pool, first, size); + refs.add(queryPool.addRefGeneric()); } - public void encodeDataUpload(MemoryManager manager, long src, VBuffer dest, long destOffset, long size) { - VBuffer staging = manager.createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + public void encodeBufferCopy(final VRef src, long srcOffset, final VRef dest, long destOffset, long size) { + try (var stack = stackPush()) { + var copy = VkBufferCopy.calloc(1, stack); + copy.get(0).srcOffset(srcOffset).dstOffset(destOffset).size(size); + vkCmdCopyBuffer(buffer, src.get().buffer(), dest.get().buffer(), copy); + } + + addBufferRef(src); + addBufferRef(dest); + } + + public void encodeDataUpload(MemoryManager manager, long src, final VRef dest, long destOffset, long size) { + VRef staging = manager.createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); - long ptr = staging.map(); + staging.get().setDebugUtilsObjectName("Data Upload Host Staging"); + long ptr = staging.get().map(); MemoryUtil.memCopy(src, ptr, size); - staging.unmap(); + staging.get().unmap(); try (var stack = stackPush()) { var copy = VkBufferCopy.calloc(1, stack); copy.get(0).srcOffset(0).dstOffset(destOffset).size(size); - vkCmdCopyBuffer(buffer, staging.buffer(), dest.buffer(), copy); + vkCmdCopyBuffer(buffer, staging.get().buffer(), dest.get().buffer(), copy); } - transientResources.add(staging); + addBufferRef(staging); + addBufferRef(dest); + + staging.close(); } - public void encodeImageUpload(MemoryManager manager, long src, VImage dest, long srcSize, int destLayout) { - VBuffer staging = manager.createBuffer(srcSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + public void encodeImageUpload(MemoryManager manager, long src, final VRef dest, long srcSize, int destLayout) { + VRef staging = manager.createBuffer(srcSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); - long ptr = staging.map(); + staging.get().setDebugUtilsObjectName("Image Upload Host Staging"); + long ptr = staging.get().map(); MemoryUtil.memCopy(src, ptr, srcSize); - staging.unmap(); + staging.get().unmap(); try (var stack = stackPush()) { var copy = VkBufferImageCopy.calloc(1, stack); copy.get(0).bufferOffset(0).bufferImageHeight(0).bufferRowLength(0) .imageOffset(o -> o.set(0, 0, 0)) - .imageExtent(extent -> extent.set(dest.width, dest.height, dest.depth)) + .imageExtent(extent -> extent.set(dest.get().width, dest.get().height, dest.get().depth)) .imageSubresource(s -> s.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT).baseArrayLayer(0).layerCount(1).mipLevel(0)); - vkCmdCopyBufferToImage(buffer, staging.buffer(), dest.image(), destLayout, copy); + vkCmdCopyBufferToImage(buffer, staging.get().buffer(), dest.get().image(), destLayout, copy); } - transientResources.add(staging); + addBufferRef(staging); + addImageRef(dest); + + staging.close(); } public void encodeMemoryBarrier() { @@ -104,109 +213,108 @@ public void encodeMemoryBarrier() { } } - public void addTransientResource(TrackedResourceObject resource) { - transientResources.add(resource); - } - public static int dstStageToAccess(int dstStage) { - switch (dstStage) { - case VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT: - return VK_ACCESS_MEMORY_READ_BIT; - case VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT: - return VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - case VK_PIPELINE_STAGE_VERTEX_INPUT_BIT: - return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - case VK_PIPELINE_STAGE_VERTEX_SHADER_BIT: - case VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT: - case VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT: - case VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT: - case VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT: - case VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT: - case VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR: - return VK_ACCESS_SHADER_READ_BIT; - case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT: - return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - case VK_PIPELINE_STAGE_TRANSFER_BIT: - return VK_ACCESS_TRANSFER_READ_BIT; - case VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR: - return VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT; - default: - return VK_ACCESS_MEMORY_READ_BIT; - } + return switch (dstStage) { + case VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT -> VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + case VK_PIPELINE_STAGE_VERTEX_INPUT_BIT -> VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + case VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR -> + VK_ACCESS_SHADER_READ_BIT; + case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT -> VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + case VK_PIPELINE_STAGE_TRANSFER_BIT -> VK_ACCESS_TRANSFER_READ_BIT; + case VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR -> + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT; + default -> VK_ACCESS_MEMORY_READ_BIT; + }; } public static int srcStageToAccess(int srcStage) { - switch (srcStage) { - case VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT: - return VK_ACCESS_MEMORY_WRITE_BIT; - case VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT: - return VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - case VK_PIPELINE_STAGE_VERTEX_INPUT_BIT: - return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - case VK_PIPELINE_STAGE_VERTEX_SHADER_BIT: - case VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT: - case VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT: - case VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT: - case VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT: - case VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT: - case VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR: - return VK_ACCESS_SHADER_WRITE_BIT; - case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT: - return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - case VK_PIPELINE_STAGE_TRANSFER_BIT: - return VK_ACCESS_TRANSFER_WRITE_BIT; - case VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR: - return VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_SHADER_WRITE_BIT; - default: - return VK_ACCESS_MEMORY_WRITE_BIT; - } + return switch (srcStage) { + case VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT -> VK_ACCESS_INDIRECT_COMMAND_READ_BIT; + case VK_PIPELINE_STAGE_VERTEX_INPUT_BIT -> VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + case VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR -> + VK_ACCESS_SHADER_WRITE_BIT; + case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT -> VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + case VK_PIPELINE_STAGE_TRANSFER_BIT -> VK_ACCESS_TRANSFER_WRITE_BIT; + case VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR -> + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_SHADER_WRITE_BIT; + default -> VK_ACCESS_MEMORY_WRITE_BIT; + }; } - public void encodeBufferBarrier(VBuffer buffer, long offset, long size) { + public void encodeBufferBarrier(final VRef buffer, long offset, long size) { encodeBufferBarrier(buffer, offset, size, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); } - public void encodeBufferBarrier(VBuffer buffer, long offset, long size, int srcStage, int dstStage) { + public void encodeBufferBarrier(final VRef buffer, long offset, long size, int srcStage, int dstStage) { try (var stack = stackPush()) { var barrier = VkBufferMemoryBarrier.calloc(1, stack); barrier.get(0).sType$Default().srcAccessMask(srcStageToAccess(srcStage)) - .dstAccessMask(dstStageToAccess(dstStage)).buffer(buffer.buffer()) + .dstAccessMask(dstStageToAccess(dstStage)).buffer(buffer.get().buffer()) .offset(offset).size(size); vkCmdPipelineBarrier(this.buffer, srcStage, dstStage, 0, null, barrier, null); } + + addBufferRef(buffer); + } + + public int srcLayoutToStage(int srcLayout) { + return switch (srcLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED -> VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL -> VK_PIPELINE_STAGE_TRANSFER_BIT; + case VK_IMAGE_LAYOUT_GENERAL -> VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL -> + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; + default -> VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + }; } - public void encodeImageTransition(VImage image, int src, int dst, int aspectMask, int mipLevels) { - encodeImageTransition(image, src, dst, aspectMask, mipLevels, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + public int layoutToAccess(int srcLayout) { + return switch (srcLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED -> 0; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL -> VK_ACCESS_TRANSFER_READ_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL -> VK_ACCESS_TRANSFER_WRITE_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL -> VK_ACCESS_SHADER_READ_BIT; + default -> VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + }; } - public void encodeImageTransition(VImage image, int src, int dst, int aspectMask, int mipLevels, int srcStage, int dstStage) { + public int dstLayoutToStage(int dstLayout) { + return switch (dstLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED -> VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL -> VK_PIPELINE_STAGE_TRANSFER_BIT; + case VK_IMAGE_LAYOUT_GENERAL -> VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL -> + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; + default -> VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + }; + } + + public void encodeImageTransition(VRef image, int src, int dst, int aspectMask, int mipLevels) { try (var stack = stackPush()) { var barrier = VkImageMemoryBarrier.calloc(1, stack); - barrier.get(0).sType$Default().srcAccessMask(srcStageToAccess(srcStage)) - .dstAccessMask(dstStageToAccess(dstStage)).oldLayout(src).newLayout(dst).image(image.image()) + barrier.get(0).sType$Default().oldLayout(src).newLayout(dst).image(image.get().image()) .subresourceRange().aspectMask(aspectMask).baseMipLevel(0).levelCount(mipLevels).baseArrayLayer(0) .layerCount(VK_REMAINING_ARRAY_LAYERS); + + int srcStage = srcLayoutToStage(src); + int dstStage = dstLayoutToStage(dst); + barrier.srcAccessMask(layoutToAccess(src)); + barrier.dstAccessMask(layoutToAccess(dst)); + vkCmdPipelineBarrier(this.buffer, srcStage, dstStage, 0, null, null, barrier); } + addImageRef(image); } - @Override - public long address() { - return buffer.address(); - } - - @Override - public void free() { - throw new IllegalStateException(); + protected void free() { + vkFreeCommandBuffers(pool.get().device, pool.get().pool, buffer == null ? finalizedBuffer : buffer); + refs.forEach(VRef::close); + refs.clear(); } - void freeInternal() { - free0(); - vkFreeCommandBuffers(pool.device, pool.pool, buffer); - transientResources.forEach(TrackedResourceObject::free); - transientResources.clear(); + public void setDebugUtilsObjectName(String name) { + Vulkanite.INSTANCE.getCtx().setDebugUtilsObjectName(buffer.address(), VK_OBJECT_TYPE_COMMAND_BUFFER, name); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/cmd/VCommandPool.java b/src/main/java/me/cortex/vulkanite/lib/cmd/VCommandPool.java index 279a82a..088f90a 100644 --- a/src/main/java/me/cortex/vulkanite/lib/cmd/VCommandPool.java +++ b/src/main/java/me/cortex/vulkanite/lib/cmd/VCommandPool.java @@ -1,6 +1,8 @@ package me.cortex.vulkanite.lib.cmd; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VRef; +import me.cortex.vulkanite.lib.base.VObject; import org.lwjgl.PointerBuffer; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkCommandBuffer; @@ -9,15 +11,16 @@ import org.lwjgl.vulkan.VkDevice; import java.nio.LongBuffer; -import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.ArrayList; +import java.util.List; import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; -public class VCommandPool extends TrackedResourceObject { +public class VCommandPool extends VObject { final VkDevice device; - final long pool; + public final long pool; public VCommandPool(VkDevice device, int flags) { this(device, 0, flags); } @@ -35,15 +38,15 @@ public VCommandPool(VkDevice device, int family, int flags) { } } - public synchronized VCmdBuff createCommandBuffer() { - return createCommandBuffers(1)[0]; + public synchronized VRef createCommandBuffer() { + return createCommandBuffers(1).get(0); } - public synchronized VCmdBuff[] createCommandBuffers(int count) { - return createCommandBuffers(count, 0); + public synchronized List> createCommandBuffers(int count) { + return createCommandBuffers(count, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); } - public synchronized VCmdBuff[] createCommandBuffers(int count, int level) { + public synchronized List> createCommandBuffers(int count, int level, int flags) { try (MemoryStack stack = MemoryStack.stackPush()){ PointerBuffer pCommandBuffer = stack.mallocPointer(count); _CHECK_(vkAllocateCommandBuffers(device, @@ -54,32 +57,20 @@ public synchronized VCmdBuff[] createCommandBuffers(int count, int level) { .level(level) .commandBufferCount(count), pCommandBuffer), "Failed to create command buffer"); - VCmdBuff[] buffers = new VCmdBuff[count]; + List> buffers = new ArrayList<>(); for (int i = 0; i < count; i++) { - buffers[i] = new VCmdBuff(this, new VkCommandBuffer(pCommandBuffer.get(i), device)); + buffers.add(new VRef<>(new VCmdBuff(new VRef<>(this), new VkCommandBuffer(pCommandBuffer.get(i), device), flags))); } return buffers; } } - private final ConcurrentLinkedDeque toRelease = new ConcurrentLinkedDeque<>(); - void free(VCmdBuff cmdBuff) { - toRelease.add(cmdBuff); - } - - public void doReleases() { - while (!toRelease.isEmpty()) { - toRelease.poll().freeInternal(); - } - } - - public void releaseNow(VCmdBuff cmd) { - cmd.freeInternal(); - } - @Override public void free() { - free0(); vkDestroyCommandPool(device, pool, null); } + + public void setDebugUtilsObjectName(String name) { + Vulkanite.INSTANCE.getCtx().setDebugUtilsObjectName(pool, VK_OBJECT_TYPE_COMMAND_POOL, name); + } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorSetLayoutBuilder.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorSetLayoutBuilder.java index b2f4d6c..bffcb81 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorSetLayoutBuilder.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorSetLayoutBuilder.java @@ -2,6 +2,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.VkDescriptorSetLayoutBinding; import org.lwjgl.vulkan.VkDescriptorSetLayoutCreateInfo; @@ -45,7 +46,7 @@ public DescriptorSetLayoutBuilder(int flags){ this.flags = flags; } - public VDescriptorSetLayout build(VContext ctx) { + public VRef build(VContext ctx) { try (var stack = stackPush()) { var info = VkDescriptorSetLayoutCreateInfo.calloc(stack) .sType$Default() @@ -66,7 +67,7 @@ public VDescriptorSetLayout build(VContext ctx) { LongBuffer pBuffer = stack.mallocLong(1); _CHECK_(vkCreateDescriptorSetLayout(ctx.device, info, null, pBuffer)); - return new VDescriptorSetLayout(ctx, pBuffer.get(0), types.toIntArray()); + return VDescriptorSetLayout.create(ctx, pBuffer.get(0), types.toIntArray()); } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java index 9811c51..4303fa3 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.descriptors; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VAccelerationStructure; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.other.VImageView; @@ -12,25 +13,38 @@ import org.lwjgl.vulkan.VkWriteDescriptorSet; import org.lwjgl.vulkan.VkWriteDescriptorSetAccelerationStructureKHR; +import java.util.ArrayList; +import java.util.List; + import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; import static org.lwjgl.vulkan.VK10.*; -import java.util.List; - public class DescriptorUpdateBuilder { private final VContext ctx; private final MemoryStack stack; private final VkWriteDescriptorSet.Buffer updates; - private final VImageView placeholderImageView; + private final VRef placeholderImageView; + private ArrayList bulkBufferInfos = new ArrayList<>(); + private ArrayList bulkImageInfos = new ArrayList<>(); private ShaderReflection.Set refSet = null; + private long set; + private VRef setRef; public DescriptorUpdateBuilder(VContext ctx, int maxUpdates) { this(ctx, maxUpdates, null); } - public DescriptorUpdateBuilder(VContext ctx, int maxUpdates, VImageView placeholderImageView) { + public DescriptorUpdateBuilder(VContext ctx, int maxUpdates, final VRef placeholderImageView) { this.ctx = ctx; - this.stack = MemoryStack.stackPush(); + // this.stack = MemoryStack.stackPush(); + int objSize = Integer.max( + Integer.max( + VkDescriptorBufferInfo.SIZEOF, + VkDescriptorImageInfo.SIZEOF), + VkWriteDescriptorSetAccelerationStructureKHR.SIZEOF); + objSize = ((objSize + 15) / 16) * 16; + this.stack = MemoryStack.create(1024 + maxUpdates * VkWriteDescriptorSet.SIZEOF + maxUpdates * objSize); + this.stack.push(); this.updates = VkWriteDescriptorSet.calloc(maxUpdates, stack); this.placeholderImageView = placeholderImageView; } @@ -39,29 +53,31 @@ public DescriptorUpdateBuilder(VContext ctx, ShaderReflection.Set refSet) { this(ctx, refSet, null); } - public DescriptorUpdateBuilder(VContext ctx, ShaderReflection.Set refSet, VImageView placeholderImageView) { + public DescriptorUpdateBuilder(VContext ctx, ShaderReflection.Set refSet, final VRef placeholderImageView) { this(ctx, refSet.bindings().size(), placeholderImageView); this.refSet = refSet; } - private long viewOrPlaceholder(VImageView v) { + private long viewOrPlaceholder(VRef v) { if (v == null && placeholderImageView == null) return 0; - return v == null ? placeholderImageView.view : v.view; + return v == null ? placeholderImageView.get().view : v.get().view; } - private long set; - public DescriptorUpdateBuilder set(long set) { - this.set = set; + public DescriptorUpdateBuilder set(VRef set) { + this.set = set.get().set; + this.setRef = set.addRef(); return this; } - public DescriptorUpdateBuilder buffer(int binding, VBuffer buffer) { + public DescriptorUpdateBuilder buffer(int binding, final VRef buffer) { return buffer(binding, buffer, 0, VK_WHOLE_SIZE); } - public DescriptorUpdateBuilder buffer(int binding, VBuffer buffer, long offset, long range) { + + public DescriptorUpdateBuilder buffer(int binding, final VRef buffer, long offset, long range) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } + setRef.get().addRef(binding, buffer.addRefGeneric()); updates.get() .sType$Default() .dstBinding(binding) @@ -70,21 +86,22 @@ public DescriptorUpdateBuilder buffer(int binding, VBuffer buffer, long offset, .descriptorCount(1) .pBufferInfo(VkDescriptorBufferInfo .calloc(1, stack) - .buffer(buffer.buffer()) + .buffer(buffer.get().buffer()) .offset(offset) .range(range)); return this; } - public DescriptorUpdateBuilder buffer(int binding, int dstArrayElement, List buffers) { + public DescriptorUpdateBuilder buffer(int binding, int dstArrayElement, final List> buffers) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } - var bufInfo = VkDescriptorBufferInfo.calloc(buffers.size(), stack); + var bufInfo = VkDescriptorBufferInfo.calloc(buffers.size()); for (int i = 0; i < buffers.size(); i++) { + setRef.get().addRef(binding + dstArrayElement + i, buffers.get(i).addRefGeneric()); bufInfo.get(i) - .buffer(buffers.get(i).buffer()) + .buffer(buffers.get(i).get().buffer()) .offset(0) .range(VK_WHOLE_SIZE); } @@ -96,18 +113,44 @@ public DescriptorUpdateBuilder buffer(int binding, int dstArrayElement, List buffer, List offsets) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } + var bufInfo = VkDescriptorBufferInfo.calloc(offsets.size()); + for (int i = 0; i < offsets.size(); i++) { + setRef.get().addRef(binding + dstArrayElement + i, buffer.addRefGeneric()); + bufInfo.get(i) + .buffer(buffer.get().buffer()) + .offset(offsets.get(i)) + .range(VK_WHOLE_SIZE); + } + updates.get() + .sType$Default() + .dstBinding(binding) + .dstSet(set) + .dstArrayElement(dstArrayElement) + .descriptorType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) + .descriptorCount(offsets.size()) + .pBufferInfo(bufInfo); + bulkBufferInfos.add(bufInfo); return this; } - public DescriptorUpdateBuilder uniform(int binding, VBuffer buffer) { + public DescriptorUpdateBuilder uniform(int binding, final VRef buffer) { return uniform(binding, buffer, 0, VK_WHOLE_SIZE); } - public DescriptorUpdateBuilder uniform(int binding, VBuffer buffer, long offset, long range) { + + public DescriptorUpdateBuilder uniform(int binding, final VRef buffer, long offset, long range) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } + setRef.get().addRef(binding, buffer.addRefGeneric()); updates.get() .sType$Default() .dstBinding(binding) @@ -116,19 +159,20 @@ public DescriptorUpdateBuilder uniform(int binding, VBuffer buffer, long offset, .descriptorCount(1) .pBufferInfo(VkDescriptorBufferInfo .calloc(1, stack) - .buffer(buffer.buffer()) + .buffer(buffer.get().buffer()) .offset(offset) .range(range)); return this; } - public DescriptorUpdateBuilder acceleration(int binding, VAccelerationStructure... structures) { + public DescriptorUpdateBuilder acceleration(int binding, VRef... structures) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } var buff = stack.mallocLong(structures.length); for (var structure : structures) { - buff.put(structure.structure); + setRef.get().addRef(binding, structure.addRefGeneric()); + buff.put(structure.get().structure); } buff.rewind(); updates.get() @@ -143,12 +187,13 @@ public DescriptorUpdateBuilder acceleration(int binding, VAccelerationStructure. return this; } - public DescriptorUpdateBuilder imageStore(int binding, int dstArrayElement, List views) { + public DescriptorUpdateBuilder imageStore(int binding, int dstArrayElement, final List> views) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } - var imgInfo = VkDescriptorImageInfo.calloc(views.size(), stack); + var imgInfo = VkDescriptorImageInfo.calloc(views.size()); for (int i = 0; i < views.size(); i++) { + setRef.get().addRef(binding, views.get(i).addRefGeneric()); imgInfo.get(i) .imageLayout(VK_IMAGE_LAYOUT_GENERAL) .imageView(viewOrPlaceholder(views.get(i))); @@ -160,15 +205,19 @@ public DescriptorUpdateBuilder imageStore(int binding, int dstArrayElement, List .descriptorType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) .descriptorCount(views.size()) .pImageInfo(imgInfo); + bulkImageInfos.add(imgInfo); return this; } - public DescriptorUpdateBuilder imageStore(int binding, VImageView view) { + + public DescriptorUpdateBuilder imageStore(int binding, final VRef view) { return imageStore(binding, VK_IMAGE_LAYOUT_GENERAL, view); } - public DescriptorUpdateBuilder imageStore(int binding, int layout, VImageView view) { + + public DescriptorUpdateBuilder imageStore(int binding, int layout, final VRef view) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } + setRef.get().addRef(binding, view.addRefGeneric()); updates.get() .sType$Default() .dstBinding(binding) @@ -182,14 +231,15 @@ public DescriptorUpdateBuilder imageStore(int binding, int layout, VImageView vi return this; } - public DescriptorUpdateBuilder imageSampler(int binding, VImageView view, VSampler sampler) { + public DescriptorUpdateBuilder imageSampler(int binding, final VRef view, VRef sampler) { return imageSampler(binding, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, view, sampler); } - public DescriptorUpdateBuilder imageSampler(int binding, int layout, VImageView view, VSampler sampler) { + public DescriptorUpdateBuilder imageSampler(int binding, int layout, final VRef view, VRef sampler) { if (refSet != null && refSet.getBindingAt(binding) == null) { return this; } + setRef.get().addRef(binding, view.addRefGeneric()); updates.get() .sType$Default() .dstBinding(binding) @@ -200,7 +250,7 @@ public DescriptorUpdateBuilder imageSampler(int binding, int layout, VImageView .calloc(1, stack) .imageLayout(layout) .imageView(viewOrPlaceholder(view)) - .sampler(sampler.sampler)); + .sampler(sampler.get().sampler)); return this; } @@ -209,5 +259,14 @@ public void apply() { updates.rewind(); vkUpdateDescriptorSets(ctx.device, updates, null); stack.pop(); + for (var bufInfo : bulkBufferInfos) { + bufInfo.free(); + } + bulkBufferInfos.clear(); + for (var imgInfo : bulkImageInfos) { + imgInfo.free(); + } + bulkImageInfos.clear(); + setRef.close(); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorPool.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorPool.java index 9926f08..c2181c1 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorPool.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorPool.java @@ -1,102 +1,116 @@ package me.cortex.vulkanite.lib.descriptors; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.vulkan.VkDescriptorPoolCreateInfo; import org.lwjgl.vulkan.VkDescriptorPoolSize; import org.lwjgl.vulkan.VkDescriptorSetAllocateInfo; import org.lwjgl.vulkan.VkDescriptorSetVariableDescriptorCountAllocateInfo; import java.nio.LongBuffer; +import java.util.ArrayList; import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK11.VK_ERROR_OUT_OF_POOL_MEMORY; -public class VDescriptorPool extends TrackedResourceObject { +public class VDescriptorPool extends VObject { private final VContext ctx; - private final long pool; + private final ArrayList pools = new ArrayList<>(); + private final ArrayList poolFreeSizes = new ArrayList<>(); + private final VRef layout; + private final int flags; - private final long[] sets; + private final int nSetsPerPool; + private final int countPerType; - public VDescriptorPool(VContext ctx, int flags, int numSets, int... types) { + private VDescriptorPool(VContext ctx, VRef layout, int flags, int nSetsPerPool, int countPerType) { this.ctx = ctx; - this.sets = new long[numSets]; + this.layout = layout.addRef(); + this.flags = flags; + this.countPerType = countPerType; + this.nSetsPerPool = nSetsPerPool; + } - try (var stack = stackPush()) { - var sizes = VkDescriptorPoolSize.calloc(types.length, stack); - for (int i = 0; i < types.length; i++) { - sizes.get(i).type(types[i]).descriptorCount(numSets); - } - LongBuffer pPool = stack.mallocLong(1); - _CHECK_(vkCreateDescriptorPool(ctx.device, VkDescriptorPoolCreateInfo.calloc(stack) - .sType$Default() - .flags(flags) - .maxSets(numSets) - .pPoolSizes(sizes), null, pPool)); - pool = pPool.get(0); - } + public static VRef create(VContext ctx, VRef layout, int flags) { + return new VRef<>(new VDescriptorPool(ctx, layout, flags, 16, 1)); } - public VDescriptorPool(VContext ctx, int flags, int numSets, int countPerType, int... types) { - this.ctx = ctx; - this.sets = new long[numSets]; + public static VRef create(VContext ctx, VRef layout, int flags, int countPerType) { + return new VRef<>(new VDescriptorPool(ctx, layout, flags, 1, countPerType)); + } + private void createNewPool() { try (var stack = stackPush()) { - var sizes = VkDescriptorPoolSize.calloc(types.length, stack); - for (int i = 0; i < types.length; i++) { - sizes.get(i).type(types[i]).descriptorCount(numSets * countPerType); + var sizes = VkDescriptorPoolSize.calloc(layout.get().types.length, stack); + for (int i = 0; i < layout.get().types.length; i++) { + sizes.get(i).type(layout.get().types[i]).descriptorCount(nSetsPerPool * countPerType); } LongBuffer pPool = stack.mallocLong(1); _CHECK_(vkCreateDescriptorPool(ctx.device, VkDescriptorPoolCreateInfo.calloc(stack) .sType$Default() - .flags(flags) - .maxSets(numSets) + .flags(flags | VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT) + .maxSets(nSetsPerPool) .pPoolSizes(sizes), null, pPool)); - pool = pPool.get(0); + pools.add(pPool.get(0)); + poolFreeSizes.add(nSetsPerPool); } } - public void allocateSets(VDescriptorSetLayout layout, int... variableSizes) { + public VRef allocateSet(int variableSize) { + if (poolFreeSizes.isEmpty() || poolFreeSizes.get(pools.size() - 1) == 0) { + createNewPool(); + } + long pool = pools.get(pools.size() - 1); + long set; + poolFreeSizes.set(pools.size() - 1, poolFreeSizes.get(pools.size() - 1) - 1); try (var stack = stackPush()) { - var layouts = stack.mallocLong(sets.length); - for (int i = 0; i < sets.length; i++) { - layouts.put(layout.layout); - } - layouts.rewind(); - LongBuffer pDescriptorSets = stack.mallocLong(sets.length); + var pSet = stack.mallocLong(1); var allocInfo = VkDescriptorSetAllocateInfo.calloc(stack) - .sType$Default() - .descriptorPool(pool) - .pSetLayouts(layouts); - if (variableSizes != null) { - var descriptorCounts = stack.mallocInt(variableSizes.length); - for (int i = 0; i < variableSizes.length; i++) { - descriptorCounts.put(variableSizes[i]); - } - descriptorCounts.rewind(); - var variableCountInfo = VkDescriptorSetVariableDescriptorCountAllocateInfo.calloc(stack) .sType$Default() - .pDescriptorCounts(descriptorCounts); + .descriptorPool(pool) + .pSetLayouts(stack.longs(layout.get().layout)); + if (variableSize >= 0) { + var variableCountInfo = VkDescriptorSetVariableDescriptorCountAllocateInfo.calloc(stack) + .sType$Default() + .pDescriptorCounts(stack.ints(variableSize)); allocInfo.pNext(variableCountInfo.address()); } - _CHECK_(vkAllocateDescriptorSets(ctx.device, allocInfo, pDescriptorSets), - "Failed to allocate descriptor set"); - pDescriptorSets.get(sets); + int result = vkAllocateDescriptorSets(ctx.device, allocInfo, pSet); + if (result == VK_ERROR_OUT_OF_POOL_MEMORY) { + createNewPool(); + return allocateSet(variableSize); + } + _CHECK_(result); + set = pSet.get(0); } + return new VRef<>(new VDescriptorSet(new VRef<>(this), pool, set)); } - public void allocateSets(VDescriptorSetLayout layout) { - allocateSets(layout, null); + public VRef allocateSet() { + return allocateSet(-1); } - public long get(int idx) { - return sets[idx]; + public void freeSet(VDescriptorSet set) { + int index = pools.indexOf(set.poolHandle); + try (var stack = stackPush()) { + var pDescriptorSets = stack.mallocLong(1).put(0, set.set); + _CHECK_(vkFreeDescriptorSets(ctx.device, set.poolHandle, pDescriptorSets)); + } + poolFreeSizes.set(index, poolFreeSizes.get(index) + 1); + if (poolFreeSizes.get(index) == nSetsPerPool) { + vkDestroyDescriptorPool(ctx.device, set.poolHandle, null); + pools.remove(index); + poolFreeSizes.remove(index); + } } @Override - public void free() { - free0(); - vkDestroyDescriptorPool(ctx.device, pool, null); + protected void free() { + for (long pool : pools) { + vkDestroyDescriptorPool(ctx.device, pool, null); + } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java index 825afc7..4a2ee9e 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java @@ -1,21 +1,59 @@ package me.cortex.vulkanite.lib.descriptors; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; +import org.lwjgl.vulkan.VkCopyDescriptorSet; -public class VDescriptorSet extends TrackedResourceObject { - private final VTypedDescriptorPool pool; +import static org.lwjgl.system.MemoryStack.stackPush; +import static org.lwjgl.vulkan.VK10.vkUpdateDescriptorSets; + +public class VDescriptorSet extends VObject { public final long poolHandle; public final long set; + private final VRef pool; + private final Int2ObjectArrayMap> refs = new Int2ObjectArrayMap<>(); - VDescriptorSet(VTypedDescriptorPool pool, long poolHandle, long set) { + protected VDescriptorSet(VRef pool, long poolHandle, long set) { this.pool = pool; this.poolHandle = poolHandle; this.set = set; } + public void addRef(int binding, VRef ref) { + var old = refs.put(binding, ref); + if (old != null) { + old.close(); + } + } + + public void removeRef(int binding) { + var old = refs.remove(binding); + if (old != null) { + old.close(); + } + } + @Override - public void free() { - free0(); - pool.freeSet(this); + protected void free() { + pool.get().freeSet(this); + refs.values().forEach(VRef::close); + } + + public void copyFrom(VContext ctx, VRef other, int setCapacity) { + for (var entry : other.get().refs.int2ObjectEntrySet()) { + refs.put(entry.getIntKey(), entry.getValue().addRef()); + } + + try (var stack = stackPush()) { + var setCopy = VkCopyDescriptorSet.calloc(1, stack); + setCopy.get(0) + .sType$Default() + .srcSet(other.get().set) + .dstSet(set) + .descriptorCount(setCapacity); + vkUpdateDescriptorSets(ctx.device, null, setCopy); + } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java index 5ff63cd..55d21d0 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java @@ -1,8 +1,9 @@ package me.cortex.vulkanite.lib.descriptors; import me.cortex.vulkanite.client.Vulkanite; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.Pointer; import org.lwjgl.vulkan.VkDescriptorPoolCreateInfo; import org.lwjgl.vulkan.VkDescriptorPoolSize; @@ -15,26 +16,29 @@ import static org.lwjgl.vulkan.VK10.vkCreateDescriptorPool; import static org.lwjgl.vulkan.VK10.vkDestroyDescriptorSetLayout; -public final class VDescriptorSetLayout extends TrackedResourceObject implements Pointer { +public final class VDescriptorSetLayout extends VObject implements Pointer { private final VContext ctx; public final long layout; public final int[] types; - public VDescriptorSetLayout(VContext ctx, long layout, int[] types) { + private VDescriptorSetLayout(VContext ctx, long layout, int[] types) { this.ctx = ctx; this.layout = layout; this.types = types; } + public static VRef create(VContext ctx, long layout, int[] types) { + return new VRef<>(new VDescriptorSetLayout(ctx, layout, types)); + } + @Override public long address() { return layout; } @Override - public void free() { + protected void free() { Vulkanite.INSTANCE.removePoolByLayout(this); - free0(); vkDestroyDescriptorSetLayout(ctx.device, layout, null); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java deleted file mode 100644 index c7113b4..0000000 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java +++ /dev/null @@ -1,87 +0,0 @@ -package me.cortex.vulkanite.lib.descriptors; - -import me.cortex.vulkanite.lib.base.TrackedResourceObject; -import me.cortex.vulkanite.lib.base.VContext; -import org.lwjgl.vulkan.VkDescriptorPoolCreateInfo; -import org.lwjgl.vulkan.VkDescriptorPoolSize; -import org.lwjgl.vulkan.VkDescriptorSetAllocateInfo; - -import java.nio.LongBuffer; -import java.util.ArrayList; - -import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; -import static org.lwjgl.system.MemoryStack.stackPush; -import static org.lwjgl.vulkan.VK10.*; - -public class VTypedDescriptorPool extends TrackedResourceObject { - private final VContext ctx; - private final ArrayList pools = new ArrayList<>(); - private final ArrayList poolFreeSizes = new ArrayList<>(); - private final VDescriptorSetLayout layout; - private final int flags; - - private static final int nSetsPerPool = 16; - - public VTypedDescriptorPool(VContext ctx, VDescriptorSetLayout layout, int flags) { - this.ctx = ctx; - this.layout = layout; - this.flags = flags; - } - - private void createNewPool() { - try (var stack = stackPush()) { - var sizes = VkDescriptorPoolSize.calloc(layout.types.length, stack); - for (int i = 0; i < layout.types.length; i++) { - sizes.get(i).type(layout.types[i]).descriptorCount(nSetsPerPool); - } - LongBuffer pPool = stack.mallocLong(1); - _CHECK_(vkCreateDescriptorPool(ctx.device, VkDescriptorPoolCreateInfo.calloc(stack) - .sType$Default() - .flags(flags | VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT) - .maxSets(nSetsPerPool) - .pPoolSizes(sizes), null, pPool)); - pools.add(pPool.get(0)); - poolFreeSizes.add(nSetsPerPool); - } - } - - public VDescriptorSet allocateSet() { - if (poolFreeSizes.isEmpty() || poolFreeSizes.get(pools.size() - 1) == 0) { - createNewPool(); - } - long pool = pools.get(pools.size() - 1); - long set; - poolFreeSizes.set(pools.size() - 1, poolFreeSizes.get(pools.size() - 1) - 1); - try (var stack = stackPush()) { - var pSet = stack.mallocLong(1); - _CHECK_(vkAllocateDescriptorSets(ctx.device, VkDescriptorSetAllocateInfo.calloc(stack) - .sType$Default() - .descriptorPool(pool) - .pSetLayouts(stack.mallocLong(1).put(0, layout.layout)), pSet)); - set = pSet.get(0); - } - return new VDescriptorSet(this, pool, set); - } - - public void freeSet(VDescriptorSet set) { - int index = pools.indexOf(set.poolHandle); - try (var stack = stackPush()) { - var pDescriptorSets = stack.mallocLong(1).put(0, set.set); - _CHECK_(vkFreeDescriptorSets(ctx.device, set.poolHandle, pDescriptorSets)); - } - poolFreeSizes.set(index, poolFreeSizes.get(index) + 1); - if (poolFreeSizes.get(index) == nSetsPerPool) { - vkDestroyDescriptorPool(ctx.device, set.poolHandle, null); - pools.remove(index); - poolFreeSizes.remove(index); - } - } - - @Override - public void free() { - free0(); - for (long pool : pools) { - vkDestroyDescriptorPool(ctx.device, pool, null); - } - } -} diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/AccelerationStructurePool.java b/src/main/java/me/cortex/vulkanite/lib/memory/AccelerationStructurePool.java new file mode 100644 index 0000000..ea6364c --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/memory/AccelerationStructurePool.java @@ -0,0 +1,152 @@ +package me.cortex.vulkanite.lib.memory; + +import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; +import org.lwjgl.vulkan.VkAccelerationStructureCreateInfoKHR; +import org.lwjgl.vulkan.VkDevice; + +import java.nio.LongBuffer; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; +import static org.lwjgl.system.MemoryStack.stackPush; +import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; +import static org.lwjgl.vulkan.KHRAccelerationStructure.vkCreateAccelerationStructureKHR; +import static org.lwjgl.vulkan.KHRBufferDeviceAddress.VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; +import static org.lwjgl.vulkan.VK10.*; + +public class AccelerationStructurePool { + private static final int PAGE_SIZE = 1024; + private static final int BLOCK_NUM_PAGES = 128 * 1024; + private static final int BUFFER_USAGE = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; + + public static class Block { + private final VRef buffer; + + private final BitSet vacant; + public int maxIndex = 0; + + private Block(MemoryManager memoryManager) { + buffer = memoryManager.createBuffer( + PAGE_SIZE * BLOCK_NUM_PAGES, + BUFFER_USAGE, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + PAGE_SIZE, + 0); + vacant = new BitSet(BLOCK_NUM_PAGES); + vacant.set(0, BLOCK_NUM_PAGES); + } + + private int allocate_n_pages(int count) { + int pos = vacant.nextSetBit(0); + outer: while (pos != -1) { + for (int offset = 1; offset < count; offset++) { + if (!vacant.get(offset + pos)) { + pos = vacant.nextSetBit(offset + pos + 1); + continue outer; + } + } + break; + } + if (pos == -1) { + throw new IllegalStateException(); + } + vacant.clear(pos, pos + count); + maxIndex = Math.max(maxIndex, pos + count); + return pos; + } + + public void free_n_pages(int pos, int count) { + vacant.set(pos, pos + count); + + maxIndex = vacant.previousClearBit(maxIndex) + 1; + } + + public long allocate(long size) { + int count = (int) Math.ceil((double) size / PAGE_SIZE); + try { + long pos = allocate_n_pages(count); + return pos * PAGE_SIZE; + } catch (IllegalStateException e) { + return -1; + } + } + + public void free(long offset, long size) { + int count = (int) Math.ceil((double) size / PAGE_SIZE); + free_n_pages((int) (offset / PAGE_SIZE), count); + } + } + + public static class AccelerationStructurePooled extends VAccelerationStructure { + private final Block block; + private final long offset; + private final long size; + + public AccelerationStructurePooled(VkDevice device, long structure, Block block, long offset, long size) { + super(device, structure, block.buffer.addRef()); + this.block = block; + this.offset = offset; + this.size = size; + } + + @Override + public void free() { + super.free(); + block.free(offset, size); + } + } + + private final List blocks = new ArrayList<>(); + + private final VContext ctx; + + public AccelerationStructurePool(VContext ctx) { + this.ctx = ctx; + blocks.add(new Block(ctx.memory)); + } + + public VRef createAcceleration(long size, int type) { + if (size > PAGE_SIZE * BLOCK_NUM_PAGES) { + return ctx.memory.createAcceleration(size, 256, BUFFER_USAGE, type); + } + + Block block = null; + long offset = -1; + + for (Block b : blocks) { + offset = b.allocate(size); + if (offset != -1) { + block = b; + break; + } + } + + if (offset == -1) { + block = new Block(ctx.memory); + blocks.add(block); + offset = block.allocate(size); + } + + AccelerationStructurePooled structure; + + try (var stack = stackPush()) { + LongBuffer pAccelerationStructure = stack.mallocLong(1); + _CHECK_(vkCreateAccelerationStructureKHR(ctx.device, VkAccelerationStructureCreateInfoKHR + .calloc(stack) + .sType$Default() + .type(type) + .size(size) + .buffer(block.buffer.get().buffer()) + .offset(offset), null, pAccelerationStructure), + "Failed to create acceleration acceleration structure"); + structure = new AccelerationStructurePooled(ctx.device, pAccelerationStructure.get(0), block, offset, size); + } + + return new VRef<>(structure); + } + +} diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/HandleDescriptorManger.java b/src/main/java/me/cortex/vulkanite/lib/memory/HandleDescriptorManger.java deleted file mode 100644 index d50ab0b..0000000 --- a/src/main/java/me/cortex/vulkanite/lib/memory/HandleDescriptorManger.java +++ /dev/null @@ -1,38 +0,0 @@ -package me.cortex.vulkanite.lib.memory; - -import com.sun.jna.Pointer; -import com.sun.jna.platform.linux.LibC; -import com.sun.jna.platform.win32.Kernel32; -import com.sun.jna.platform.win32.WinNT; -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -import me.cortex.vulkanite.client.Vulkanite; - -public class HandleDescriptorManger { - private static final Long2IntOpenHashMap USED_HANDLE_DESCRIPTORS = new Long2IntOpenHashMap(); - public static void add(long handleDescriptor) { - synchronized (USED_HANDLE_DESCRIPTORS) { - USED_HANDLE_DESCRIPTORS.addTo(handleDescriptor, 1); - } - } - - public static void close(long handleDescriptor) { - synchronized (USED_HANDLE_DESCRIPTORS) { - int val = USED_HANDLE_DESCRIPTORS.addTo(handleDescriptor, -1); - if (val <= 0) { - throw new IllegalStateException(); - } - if (val == 1) { - USED_HANDLE_DESCRIPTORS.remove(handleDescriptor); - if (Vulkanite.IS_WINDOWS) { - if (!Kernel32.INSTANCE.CloseHandle(new WinNT.HANDLE(new Pointer(handleDescriptor)))) { - throw new IllegalStateException(); - } - } else { - if (LibC.INSTANCE.close((int) handleDescriptor) != 0) { - throw new IllegalStateException(); - } - } - } - } - } -} diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/MemoryManager.java b/src/main/java/me/cortex/vulkanite/lib/memory/MemoryManager.java index cab4579..f89ee3a 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/MemoryManager.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/MemoryManager.java @@ -6,6 +6,7 @@ import com.sun.jna.platform.win32.WinNT; import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.PointerBuffer; import org.lwjgl.util.vma.VmaAllocationCreateInfo; import org.lwjgl.vulkan.*; @@ -17,6 +18,7 @@ import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static me.cortex.vulkanite.lib.other.VUtil._CHECK_GL_ERROR_; +import static me.cortex.vulkanite.lib.other.VUtil._REPORT_GL_ERROR_; import static org.lwjgl.opengl.ARBDirectStateAccess.*; import static org.lwjgl.opengl.EXTMemoryObject.*; import static org.lwjgl.opengl.EXTMemoryObjectFD.GL_HANDLE_TYPE_OPAQUE_FD_EXT; @@ -39,7 +41,7 @@ import static org.lwjgl.vulkan.VK11.VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; public class MemoryManager { - private static final int EXTERNAL_MEMORY_HANDLE_TYPE = Vulkanite.IS_WINDOWS?VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + private static final int EXTERNAL_MEMORY_HANDLE_TYPE = Vulkanite.IS_WINDOWS?VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; private final VkDevice device; private final VmaAllocator allocator; private final boolean hasDeviceAddresses; @@ -73,7 +75,7 @@ public static int acquire(VmaAllocator.Allocation allocation, VkDevice device, b _CHECK_(vkGetMemoryWin32HandleKHR(device, VkMemoryGetWin32HandleInfoKHR.calloc(stack) .sType$Default() .memory(vkMemory) - .handleType(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT), pb)); + .handleType(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT), pb)); nativeHandle = pb.get(0); } else { IntBuffer pb = stack.callocInt(1); @@ -102,14 +104,17 @@ public static int acquire(VmaAllocator.Allocation allocation, VkDevice device, b if (Vulkanite.IS_WINDOWS) { glImportMemoryWin32HandleEXT(newMemoryObject, memorySize, - GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT, nativeHandle); + GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, nativeHandle); _CHECK_GL_ERROR_(); } else { glImportMemoryFdEXT(newMemoryObject, memorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, (int) nativeHandle); _CHECK_GL_ERROR_(); + nativeHandle = -1; } + System.out.println("Imported memory object: " + newMemoryObject + " with handle: " + nativeHandle + " and size: " + ((double)memorySize / 1024 / 1024) + "MB"); + if (newMemoryObject == 0) throw new IllegalStateException(); @@ -134,16 +139,18 @@ public static void release(long memory) { glDeleteMemoryObjectsEXT(tracked.desc.glMemoryObj); _CHECK_GL_ERROR_(); if (Vulkanite.IS_WINDOWS) { - // if (!Kernel32.INSTANCE.CloseHandle(new WinNT.HANDLE(new Pointer(tracked.desc.handle)))) { - // int error = Kernel32.INSTANCE.GetLastError(); - // System.err.println("STATE MIGHT BE BROKEN! Failed to close handle: " + error); - // throw new IllegalStateException(); - // } + if (!Kernel32.INSTANCE.CloseHandle(new WinNT.HANDLE(new Pointer(tracked.desc.handle)))) { + int error = Kernel32.INSTANCE.GetLastError(); + System.err.println("STATE MIGHT BE BROKEN! Failed to close handle: " + error); + throw new IllegalStateException(); + } } else { - int code = 0; - if ((code = LibC.INSTANCE.close((int) tracked.desc.handle)) != 0) { - System.err.println("STATE MIGHT BE BROKEN! Failed to close FD: " + code); - throw new IllegalStateException(); + if (tracked.desc.handle != -1) { + int code = 0; + if ((code = LibC.INSTANCE.close((int) tracked.desc.handle)) != 0) { + System.err.println("STATE MIGHT BE BROKEN! Failed to close FD: " + code); + throw new IllegalStateException(); + } } } MEMORY_TO_HANDLES.remove(memory); @@ -154,7 +161,7 @@ public static void release(long memory) { } }; - public VGBuffer createSharedBuffer(long size, int usage, int properties) { + public VRef createSharedBuffer(long size, int usage, int properties) { try (var stack = stackPush()) { var bufferCreateInfo = VkBufferCreateInfo .calloc(stack) @@ -167,7 +174,7 @@ public VGBuffer createSharedBuffer(long size, int usage, int properties) { var allocationCreateInfo = VmaAllocationCreateInfo.calloc(stack) .requiredFlags(properties); - + var alloc = allocator.allocShared(bufferCreateInfo, allocationCreateInfo); int memoryObject = ExternalMemoryTracker.acquire(alloc, device, alloc.isDedicated()); @@ -175,14 +182,15 @@ public VGBuffer createSharedBuffer(long size, int usage, int properties) { int glId = glCreateBuffers(); glNamedBufferStorageMemEXT(glId, size, memoryObject, alloc.ai.offset()); _CHECK_GL_ERROR_(); - return new VGBuffer(alloc, glId); + return VGBuffer.create(alloc, usage, glId); } } - public VGImage createSharedImage(int width, int height, int mipLevels, int vkFormat, int glFormat, int usage, int properties) { + public VRef createSharedImage(int width, int height, int mipLevels, int vkFormat, int glFormat, int usage, int properties) { return createSharedImage(2, width, height, 1, mipLevels, vkFormat, glFormat, usage, properties); } - public VGImage createSharedImage(int dimensions, int width, int height, int depth, int mipLevels, int vkFormat, int glFormat, int usage, int properties) { + public VRef createSharedImage(int dimensions, int width, int height, int depth, int mipLevels, int vkFormat, int glFormat, int usage, int properties) { + _REPORT_GL_ERROR_(); int vkImageType = VK_IMAGE_TYPE_2D; int glImageType = GL_TEXTURE_2D; @@ -195,21 +203,28 @@ public VGImage createSharedImage(int dimensions, int width, int height, int dept glImageType = GL_TEXTURE_3D; } + System.out.println( + "Creating shared image with dimensions: " + width + "," + height + "," + depth + + " vkImageType: " + vkImageType + + " glImageType: " + glImageType + + " mipLevels: " + mipLevels + + " vkFormat: " + vkFormat + + " glFormat: " + glFormat); + try (var stack = stackPush()) { var createInfo = VkImageCreateInfo .calloc(stack) .sType$Default() - .usage(usage) .pNext(VkExternalMemoryImageCreateInfo.calloc(stack) .sType$Default() .handleTypes(EXTERNAL_MEMORY_HANDLE_TYPE)) + .usage(usage) .format(vkFormat) .imageType(vkImageType) .mipLevels(mipLevels) .arrayLayers(1) .tiling(VK_IMAGE_TILING_OPTIMAL) .initialLayout(VK_IMAGE_LAYOUT_UNDEFINED) - .usage(usage) .samples(VK_SAMPLE_COUNT_1_BIT); createInfo.extent().width(width).height(height).depth(depth); @@ -221,6 +236,8 @@ public VGImage createSharedImage(int dimensions, int width, int height, int dept int memoryObject = ExternalMemoryTracker.acquire(alloc, device, alloc.isDedicated()); int glId = glCreateTextures(glImageType); + glTextureParameteri(glId, GL_TEXTURE_TILING_EXT, GL_OPTIMAL_TILING_EXT); + _CHECK_GL_ERROR_(); switch(glImageType) { case GL_TEXTURE_1D: @@ -247,15 +264,15 @@ public VGImage createSharedImage(int dimensions, int width, int height, int dept } _CHECK_GL_ERROR_(); - return new VGImage(alloc, width, height, depth, mipLevels, vkFormat, glFormat, glId); + return VGImage.create(alloc, width, height, depth, mipLevels, vkFormat, glFormat, glId); } } - public VBuffer createBuffer(long size, int usage, int properties) { + public VRef createBuffer(long size, int usage, int properties) { return createBuffer(size, usage, properties, 0L, 0); } - public VBuffer createBuffer(long size, int usage, int properties, long alignment, int vmaFlags) { + public VRef createBuffer(long size, int usage, int properties, long alignment, int vmaFlags) { try (var stack = stackPush()) { var alloc = allocator.alloc(0, VkBufferCreateInfo .calloc(stack) @@ -266,11 +283,11 @@ public VBuffer createBuffer(long size, int usage, int properties, long alignment .usage(VMA_MEMORY_USAGE_AUTO) .requiredFlags(properties), alignment); - return new VBuffer(alloc); + return VBuffer.create(alloc, usage); } } - public VImage createImage2D(int width, int height, int mipLevels, int vkFormat, int usage, int properties) { + public VRef createImage2D(int width, int height, int mipLevels, int vkFormat, int usage, int properties) { try (var stack = stackPush()) { var alloc = allocator.alloc(0, VkImageCreateInfo .calloc(stack) @@ -287,11 +304,11 @@ public VImage createImage2D(int width, int height, int mipLevels, int vkFormat, VmaAllocationCreateInfo.calloc(stack) .usage(VMA_MEMORY_USAGE_AUTO) .requiredFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); - return new VImage(alloc, width, height, 1, mipLevels, vkFormat); + return VImage.create(alloc, width, height, 1, mipLevels, vkFormat); } } - public VAccelerationStructure createAcceleration(long size, int alignment, int usage, int type) { + public VRef createAcceleration(long size, int alignment, int usage, int type) { var buffer = createBuffer(size, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, alignment, 0); try (var stack = stackPush()) { LongBuffer pAccelerationStructure = stack.mallocLong(1); @@ -300,9 +317,30 @@ public VAccelerationStructure createAcceleration(long size, int alignment, int u .sType$Default() .type(type) .size(size) - .buffer(buffer.buffer()), null, pAccelerationStructure), + .buffer(buffer.get().buffer()), null, pAccelerationStructure), + "Failed to create acceleration acceleration structure"); + var ret = VAccelerationStructure.create(device, pAccelerationStructure.get(0), buffer); + buffer.close(); + return ret; + } + } + + public VRef createAcceleration(VRef buffer, long offset, long size, int type) { + try (var stack = stackPush()) { + LongBuffer pAccelerationStructure = stack.mallocLong(1); + _CHECK_(vkCreateAccelerationStructureKHR(device, VkAccelerationStructureCreateInfoKHR + .calloc(stack) + .sType$Default() + .type(type) + .size(size) + .buffer(buffer.get().buffer()) + .offset(offset), null, pAccelerationStructure), "Failed to create acceleration acceleration structure"); - return new VAccelerationStructure(device, pAccelerationStructure.get(0), buffer); + return VAccelerationStructure.create(device, pAccelerationStructure.get(0), buffer); } } + + public void dumpStats() { + System.out.println("VMA JSON:\n" + allocator.dumpJson(false)); + } } diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/PoolLinearAllocator.java b/src/main/java/me/cortex/vulkanite/lib/memory/PoolLinearAllocator.java new file mode 100644 index 0000000..171db37 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/memory/PoolLinearAllocator.java @@ -0,0 +1,68 @@ +package me.cortex.vulkanite.lib.memory; + +import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; + +import java.util.Stack; + +import static org.lwjgl.vulkan.VK10.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + +public class PoolLinearAllocator { + private final int usage; + private final int properties; + private final int vmaFlags; + private final long poolSize; + private final long alignment; + + private VRef buffer; + private long currentOffset; + + private final VContext ctx; + + public record BufferRegion(VRef buffer, long offset, long size, long deviceAddress) { } + + public PoolLinearAllocator(VContext ctx, int usage, long poolSize, long alignment) { + this(ctx, usage, poolSize, alignment, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0); + } + + public PoolLinearAllocator(VContext ctx, int usage, long poolSize, long alignment, int properties, int vmaFlags) { + this.ctx = ctx; + this.usage = usage; + this.poolSize = poolSize; + this.alignment = alignment; + this.properties = properties; + this.vmaFlags = vmaFlags; + + this.currentOffset = 0; + + newBuffer(poolSize); + } + + private void newBuffer(long size) { + var newBuffer = ctx.memory.createBuffer(size, usage, properties, alignment, 0); + if (buffer != null) { + buffer.close(); + } + buffer = newBuffer; + currentOffset = 0; + } + + public BufferRegion allocate(long size) { + if (currentOffset + size > poolSize) { + newBuffer(Long.max(poolSize, size)); + } + + long deviceAddress = buffer.get().hasDeviceAddress() ? buffer.get().deviceAddress() + currentOffset : 0; + BufferRegion region = new BufferRegion(buffer, currentOffset, size, deviceAddress); + currentOffset = (currentOffset + size + alignment - 1) & ~(alignment - 1); + + return region; + } + + public void reset() { + if (buffer != null) { + buffer.close(); + } + currentOffset = 0; + } +} diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VAccelerationStructure.java b/src/main/java/me/cortex/vulkanite/lib/memory/VAccelerationStructure.java index 1b71a36..824b8b0 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VAccelerationStructure.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VAccelerationStructure.java @@ -1,25 +1,23 @@ package me.cortex.vulkanite.lib.memory; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkAccelerationStructureDeviceAddressInfoKHR; import org.lwjgl.vulkan.VkDevice; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; import static org.lwjgl.vulkan.KHRAccelerationStructure.*; -public class VAccelerationStructure extends TrackedResourceObject { +public class VAccelerationStructure extends VObject { public final long structure; - public final VBuffer buffer; + private final VRef buffer; + public final long deviceAddress; private final VkDevice device; - VAccelerationStructure(VkDevice device, long structure, VBuffer buffer) { + protected VAccelerationStructure(VkDevice device, long structure, final VRef buffer) { this.device = device; - this.buffer = buffer; + this.buffer = buffer.addRef(); this.structure = structure; try (MemoryStack stack = MemoryStack.stackPush()){ deviceAddress = vkGetAccelerationStructureDeviceAddressKHR(device, @@ -30,9 +28,12 @@ public class VAccelerationStructure extends TrackedResourceObject { } } + public static VRef create(VkDevice device, long structure, VRef buffer) { + return new VRef<>(new VAccelerationStructure(device, structure, buffer)); + } + public void free() { - free0(); vkDestroyAccelerationStructureKHR(device, structure, null); - buffer.free(); + buffer.close(); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java b/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java index 17753d0..851c913 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java @@ -1,32 +1,62 @@ package me.cortex.vulkanite.lib.memory; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; +import org.lwjgl.vulkan.VkDeviceOrHostAddressConstKHR; +import static org.lwjgl.vulkan.VK10.VK_OBJECT_TYPE_BUFFER; import static org.lwjgl.vulkan.VK10.VK_WHOLE_SIZE; -public class VBuffer extends TrackedResourceObject { +public class VBuffer extends VObject { private VmaAllocator.BufferAllocation allocation; + private final VkDeviceOrHostAddressConstKHR deviceAddressConst; + private final int usage; - VBuffer(VmaAllocator.BufferAllocation allocation) { + public static VRef create(VmaAllocator.BufferAllocation allocation, int usage) { + return new VRef<>(new VBuffer(allocation, usage)); + } + + protected VBuffer(VmaAllocator.BufferAllocation allocation, int usage) { this.allocation = allocation; + if (allocation.deviceAddress != -1) { + this.deviceAddressConst = VkDeviceOrHostAddressConstKHR.calloc() + .deviceAddress(allocation.deviceAddress); + } else { + this.deviceAddressConst = null; + } + this.usage = usage; } public long buffer() { return allocation.buffer; } - public void free() { - free0(); + public int usage() { + return usage; + } + + protected void free() { allocation.free(); allocation = null; } + public boolean hasDeviceAddress() { + return allocation.deviceAddress != -1; + } + public long deviceAddress() { if (allocation.deviceAddress == -1) throw new IllegalStateException(); return allocation.deviceAddress; } + public VkDeviceOrHostAddressConstKHR deviceAddressConst() { + if (allocation.deviceAddress == -1) + throw new IllegalStateException(); + return deviceAddressConst; + } + public long map() { return allocation.map(); } @@ -46,4 +76,8 @@ public void flush(long offset, long size) { public long size() { return allocation.size(); } + + public void setDebugUtilsObjectName(String name) { + Vulkanite.INSTANCE.getCtx().setDebugUtilsObjectName(buffer(), VK_OBJECT_TYPE_BUFFER, name); + } } diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VGBuffer.java b/src/main/java/me/cortex/vulkanite/lib/memory/VGBuffer.java index d69a098..c6abd60 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VGBuffer.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VGBuffer.java @@ -1,22 +1,33 @@ package me.cortex.vulkanite.lib.memory; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VRef; + import static me.cortex.vulkanite.lib.other.VUtil._CHECK_GL_ERROR_; +import static org.lwjgl.opengl.GL11C.glDeleteTextures; import static org.lwjgl.opengl.GL15C.glDeleteBuffers; public class VGBuffer extends VBuffer { public final int glId; private final long vkMemory; - VGBuffer(VmaAllocator.BufferAllocation allocation, int glId) { - super(allocation); + protected VGBuffer(VmaAllocator.BufferAllocation allocation, int usage, int glId) { + super(allocation, usage); this.glId = glId; this.vkMemory = allocation.ai.deviceMemory(); } + public static VRef create(VmaAllocator.BufferAllocation allocation, int usage, int glId) { + return new VRef<>(new VGBuffer(allocation, usage, glId)); + } + @Override - public void free() { - glDeleteBuffers(glId); - _CHECK_GL_ERROR_(); - MemoryManager.ExternalMemoryTracker.release(this.vkMemory); + protected void free() { + int glId = this.glId; + Vulkanite.INSTANCE.addSyncedCallback(() -> { + glDeleteBuffers(glId); + _CHECK_GL_ERROR_(); + MemoryManager.ExternalMemoryTracker.release(this.vkMemory); + }); super.free(); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VGImage.java b/src/main/java/me/cortex/vulkanite/lib/memory/VGImage.java index 7fd9e11..58a1769 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VGImage.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VGImage.java @@ -1,5 +1,8 @@ package me.cortex.vulkanite.lib.memory; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VRef; + import static me.cortex.vulkanite.lib.other.VUtil._CHECK_GL_ERROR_; import static org.lwjgl.opengl.GL11C.glDeleteTextures; @@ -8,17 +11,24 @@ public class VGImage extends VImage { public final int glFormat; private final long vkMemory; - VGImage(VmaAllocator.ImageAllocation allocation, int width, int height, int depth, int mipLayers, int format, int glFormat, int glId) { + protected VGImage(VmaAllocator.ImageAllocation allocation, int width, int height, int depth, int mipLayers, int format, int glFormat, int glId) { super(allocation, width, height, depth, mipLayers, format); this.glId = glId; this.glFormat = glFormat; this.vkMemory = allocation.ai.deviceMemory(); } - public void free() { - glDeleteTextures(glId); - _CHECK_GL_ERROR_(); - MemoryManager.ExternalMemoryTracker.release(this.vkMemory); + public static VRef create(VmaAllocator.ImageAllocation allocation, int width, int height, int depth, int mipLayers, int format, int glFormat, int glId) { + return new VRef<>(new VGImage(allocation, width, height, depth, mipLayers, format, glFormat, glId)); + } + + protected void free() { + int glId = this.glId; + Vulkanite.INSTANCE.addSyncedCallback(() -> { + glDeleteTextures(glId); + _CHECK_GL_ERROR_(); + MemoryManager.ExternalMemoryTracker.release(this.vkMemory); + }); super.free(); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VImage.java b/src/main/java/me/cortex/vulkanite/lib/memory/VImage.java index d8606c8..09aa04b 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VImage.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VImage.java @@ -1,8 +1,15 @@ package me.cortex.vulkanite.lib.memory; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; + import java.lang.ref.Cleaner; -public class VImage { +import static org.lwjgl.vulkan.VK10.VK_OBJECT_TYPE_BUFFER; +import static org.lwjgl.vulkan.VK10.VK_OBJECT_TYPE_IMAGE; + +public class VImage extends VObject { protected VmaAllocator.ImageAllocation allocation; public final int width; public final int height; @@ -12,7 +19,7 @@ public class VImage { public final int dimensions; - VImage(VmaAllocator.ImageAllocation allocation, int width, int height, int depth, int mipLayers, int format) { + protected VImage(VmaAllocator.ImageAllocation allocation, int width, int height, int depth, int mipLayers, int format) { this.allocation = allocation; this.width = width; this.height = height; @@ -32,7 +39,11 @@ else if(height != 1 && depth == 1) { this.dimensions = dimensions; } - public void free() { + public static VRef create(VmaAllocator.ImageAllocation allocation, int width, int height, int depth, int mipLayers, int format) { + return new VRef<>(new VImage(allocation, width, height, depth, mipLayers, format)); + } + + protected void free() { allocation.free(); allocation = null; } @@ -40,4 +51,8 @@ public void free() { public long image() { return allocation.image; } + + public void setDebugUtilsObjectName(String name) { + Vulkanite.INSTANCE.getCtx().setDebugUtilsObjectName(image(), VK_OBJECT_TYPE_IMAGE, name); + } } 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 4c5a424..311180e 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VmaAllocator.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VmaAllocator.java @@ -1,7 +1,7 @@ package me.cortex.vulkanite.lib.memory; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; - +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VObject; import org.lwjgl.PointerBuffer; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; @@ -28,12 +28,13 @@ public class VmaAllocator { private final long sharedBlockSize; - 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<>(); + private final VkExportMemoryAllocateInfo exportMemoryAllocateInfo; + private final VkExportMemoryAllocateInfo exportDedicatedMemoryAllocateInfo; + boolean testModifyFormatSupport(VkDevice device, VkImageCreateInfo imageCreateInfo) { var query = new ImageFormatQuery(imageCreateInfo.format(), imageCreateInfo.imageType(), imageCreateInfo.tiling(), imageCreateInfo.usage(), imageCreateInfo.flags()); @@ -101,6 +102,7 @@ public VmaAllocator(VkDevice device, boolean enableDeviceAddresses, long sharedB .set(device.getPhysicalDevice().getInstance(), device)) .vulkanApiVersion(VK_API_VERSION_1_2) .flags(enableDeviceAddresses ? VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT : 0); + allocatorCreateInfo.flags(allocatorCreateInfo.flags() | VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT); PointerBuffer pAllocator = stack.pointers(0); if (vmaCreateAllocator(allocatorCreateInfo, pAllocator) != VK_SUCCESS) { @@ -109,7 +111,44 @@ public VmaAllocator(VkDevice device, boolean enableDeviceAddresses, long sharedB allocator = pAllocator.get(0); - int sharedPoolMemoryTypeIndex; + { + // Create the pool for dedicated allocation + var imageCreateInfo = VkImageCreateInfo.calloc(stack) + .sType$Default() + .imageType(VK_IMAGE_TYPE_2D) + .format(VK_FORMAT_R8G8B8A8_UNORM) + .extent(e -> e.set(512, 512, 1)) + .mipLevels(1) + .arrayLayers(1) + .samples(VK_SAMPLE_COUNT_1_BIT) + .tiling(VK_IMAGE_TILING_OPTIMAL) + .usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT) + .sharingMode(VK_SHARING_MODE_EXCLUSIVE) + .initialLayout(VK_IMAGE_LAYOUT_UNDEFINED); + var allocationCreateInfo = VmaAllocationCreateInfo.calloc(stack).usage(VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE) + .requiredFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + IntBuffer pMemoryTypeIndex = stack.callocInt(1); + if (vmaFindMemoryTypeIndexForImageInfo(allocator, imageCreateInfo, allocationCreateInfo, + pMemoryTypeIndex) != VK_SUCCESS) { + throw new RuntimeException("Failed to find memory type index for shared pool"); + } + int sharedDedicatedPoolMemoryTypeIndex = pMemoryTypeIndex.get(0); + + exportDedicatedMemoryAllocateInfo = VkExportMemoryAllocateInfo.calloc() + .sType$Default() + .pNext(0) + .handleTypes(sharedHandleType); + + VmaPoolCreateInfo pci = VmaPoolCreateInfo.calloc(stack) + .memoryTypeIndex(sharedDedicatedPoolMemoryTypeIndex) + .pMemoryAllocateNext(exportDedicatedMemoryAllocateInfo.address()); + PointerBuffer pb = stack.callocPointer(1); + if (vmaCreatePool(allocator, pci, pb) != VK_SUCCESS) { + throw new RuntimeException("Failed to create sharedDedicatedPool"); + } + sharedDedicatedPool = pb.get(0); + } { var bufferCreateInfo = VkBufferCreateInfo.calloc(stack) @@ -125,30 +164,24 @@ public VmaAllocator(VkDevice device, boolean enableDeviceAddresses, long sharedB pMemoryTypeIndex) != VK_SUCCESS) { throw new RuntimeException("Failed to find memory type index for shared pool"); } - sharedPoolMemoryTypeIndex = pMemoryTypeIndex.get(0); - } - - // This object is leaked, yes... - // But we should only have one allocator anyways - exportMemoryAllocateInfo = VkExportMemoryAllocateInfo.calloc() - .sType$Default() - .pNext(0) - .handleTypes(sharedHandleType); - VmaPoolCreateInfo pci = VmaPoolCreateInfo.calloc(stack) - .memoryTypeIndex(sharedPoolMemoryTypeIndex) - .pMemoryAllocateNext(exportMemoryAllocateInfo.address()); - PointerBuffer pb = stack.callocPointer(1); - if (vmaCreatePool(allocator, pci, pb) != VK_SUCCESS) { - throw new RuntimeException("Failed to create sharedDedicatedPool"); - } - sharedDedicatedPool = pb.get(0); + int sharedPoolMemoryTypeIndex = pMemoryTypeIndex.get(0); - pci.blockSize(sharedBlockSize); - if (vmaCreatePool(allocator, pci, pb) != VK_SUCCESS) { - throw new RuntimeException("Failed to create sharedPool"); + exportMemoryAllocateInfo = VkExportMemoryAllocateInfo.calloc() + .sType$Default() + .pNext(0) + .handleTypes(sharedHandleType); + + VmaPoolCreateInfo pci = VmaPoolCreateInfo.calloc(stack) + .memoryTypeIndex(sharedPoolMemoryTypeIndex) + .blockSize(sharedBlockSize) + .pMemoryAllocateNext(exportMemoryAllocateInfo.address()); + PointerBuffer pb = stack.callocPointer(1); + if (vmaCreatePool(allocator, pci, pb) != VK_SUCCESS) { + throw new RuntimeException("Failed to create sharedPool"); + } + sharedPool = pb.get(0); } - sharedPool = pb.get(0); } } @@ -210,6 +243,9 @@ BufferAllocation alloc(long pool, VkBufferCreateInfo bufferCreateInfo, BufferAllocation alloc(long pool, VkBufferCreateInfo bufferCreateInfo, VmaAllocationCreateInfo allocationCreateInfo, long alignment) { + if (bufferCreateInfo.size() == 0) { + throw new RuntimeException("Buffer size must be greater than 0"); + } try (var stack = stackPush()) { LongBuffer pb = stack.mallocLong(1); PointerBuffer pa = stack.mallocPointer(1); @@ -232,25 +268,54 @@ SharedImageAllocation allocShared(VkImageCreateInfo imageCreateInfo, VmaAllocati testModifyFormatSupport(device, imageCreateInfo); try (var stack = stackPush()) { LongBuffer pb = stack.callocLong(1); - _CHECK_(vkCreateImage(device, imageCreateInfo, null, pb), "Failed to create VkBuffer"); + _CHECK_(vkCreateImage(device, imageCreateInfo, null, pb), "Failed to create VkImage"); long image = pb.get(0); var memReq = VkMemoryRequirements.calloc(stack); vkGetImageMemoryRequirements(device, image, memReq); - allocationCreateInfo.flags(VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) - .pool(sharedDedicatedPool) - .memoryTypeBits(memReq.memoryTypeBits()); + boolean dedicated = memReq.size() > sharedBlockSize; + if (Vulkanite.INSTANCE.IS_ZINK) { + dedicated = false; + } + + if (!dedicated) { + var dedicatedMemReq = VkMemoryDedicatedRequirements.calloc(stack) + .sType$Default() + .pNext(0); + var memReq2 = VkMemoryRequirements2.calloc(stack) + .sType$Default() + .pNext(dedicatedMemReq.address()); + vkGetImageMemoryRequirements2(device, VkImageMemoryRequirementsInfo2 + .calloc(stack) + .sType$Default() + .image(image), memReq2); + if (Vulkanite.INSTANCE.IS_ZINK) { + if (dedicatedMemReq.requiresDedicatedAllocation()) { + throw new RuntimeException("Zink does not support importing dedicated memory, however the Vulkan implementation demands it"); + } + } else { + dedicated = dedicatedMemReq.prefersDedicatedAllocation() || dedicatedMemReq.requiresDedicatedAllocation(); + } + } + + if (dedicated) { + allocationCreateInfo.flags(VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT); + allocationCreateInfo.pool(sharedDedicatedPool); + } else { + allocationCreateInfo.pool(sharedPool); + } + + allocationCreateInfo.memoryTypeBits(memReq.memoryTypeBits()); VmaAllocationInfo vai = VmaAllocationInfo.calloc(); PointerBuffer pAllocation = stack.mallocPointer(1); - _CHECK_( - vmaAllocateMemoryForImage(allocator, image, allocationCreateInfo, pAllocation, vai), - "Failed to allocate memory for image"); + _CHECK_(vmaAllocateMemoryForImage(allocator, image, allocationCreateInfo, pAllocation, vai), "Failed to allocate memory for image"); + long allocation = pAllocation.get(0); _CHECK_(vmaBindImageMemory(allocator, allocation, image), "failed to bind image memory"); - return new SharedImageAllocation(image, allocation, vai, true); + return new SharedImageAllocation(image, allocation, vai, dedicated); } } @@ -272,7 +337,7 @@ ImageAllocation alloc(long pool, VkImageCreateInfo imageCreateInfo, VmaAllocatio } } - public abstract static class Allocation extends TrackedResourceObject { + public abstract static class Allocation extends VObject { public final VmaAllocationInfo ai; public final long allocation; @@ -282,8 +347,7 @@ public Allocation(long allocation, VmaAllocationInfo info) { this.allocation = allocation; } - public void free() { - free0(); + protected void free() { // vmaFreeMemory(allocator, allocation); ai.free(); } @@ -297,7 +361,7 @@ public class BufferAllocation extends Allocation { public long buffer = 0; public final long deviceAddress; - public BufferAllocation(long buffer, long allocation, VmaAllocationInfo info, boolean hasDeviceAddress) { + protected BufferAllocation(long buffer, long allocation, VmaAllocationInfo info, boolean hasDeviceAddress) { super(allocation, info); this.buffer = buffer; if (hasDeviceAddresses && hasDeviceAddress) { @@ -313,7 +377,7 @@ public BufferAllocation(long buffer, long allocation, VmaAllocationInfo info, bo } @Override - public void free() { + protected void free() { // vkFreeMemory(); vmaDestroyBuffer(allocator, buffer, allocation); super.free(); @@ -355,17 +419,16 @@ public void flush(long offset, long size) { public class SharedBufferAllocation extends BufferAllocation { private final boolean dedicated; - public SharedBufferAllocation(long buffer, long allocation, VmaAllocationInfo info, boolean hasDeviceAddress, + protected SharedBufferAllocation(long buffer, long allocation, VmaAllocationInfo info, boolean hasDeviceAddress, boolean dedicated) { super(buffer, allocation, info, hasDeviceAddress); this.dedicated = dedicated; } @Override - public void free() { + protected void free() { vkDestroyBuffer(device, buffer, null); vmaFreeMemory(allocator, allocation); - free0(); ai.free(); } @@ -377,13 +440,13 @@ boolean isDedicated() { public class ImageAllocation extends Allocation { public final long image; - public ImageAllocation(long image, long allocation, VmaAllocationInfo info) { + protected ImageAllocation(long image, long allocation, VmaAllocationInfo info) { super(allocation, info); this.image = image; } @Override - public void free() { + protected void free() { // vkFreeMemory(); vmaDestroyImage(allocator, image, allocation); super.free(); @@ -393,17 +456,16 @@ public void free() { public class SharedImageAllocation extends ImageAllocation { private final boolean dedicated; - public SharedImageAllocation(long image, long allocation, VmaAllocationInfo info, boolean dedicated) { + protected SharedImageAllocation(long image, long allocation, VmaAllocationInfo info, boolean dedicated) { super(image, allocation, info); this.dedicated = dedicated; } @Override - public void free() { + protected void free() { // vkFreeMemory(); vkDestroyImage(device, image, null); vmaFreeMemory(allocator, allocation); - free0(); ai.free(); } 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 ee0e778..fedd1de 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/FormatConverter.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/FormatConverter.java @@ -1,6 +1,6 @@ package me.cortex.vulkanite.lib.other; -import net.coderbot.iris.gl.texture.InternalTextureFormat; +import net.irisshaders.iris.gl.texture.InternalTextureFormat; import static org.lwjgl.opengl.GL11C.GL_RGB8; import static org.lwjgl.opengl.GL11C.GL_RGBA16; diff --git a/src/main/java/me/cortex/vulkanite/lib/other/VImageView.java b/src/main/java/me/cortex/vulkanite/lib/other/VImageView.java index 665a4cb..18ff1f0 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/VImageView.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/VImageView.java @@ -1,7 +1,8 @@ package me.cortex.vulkanite.lib.other; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VImage; import org.lwjgl.vulkan.VkImageViewCreateInfo; @@ -11,15 +12,15 @@ import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; -public class VImageView extends TrackedResourceObject { +public class VImageView extends VObject { private final VContext ctx; - public final VImage image; + public final VRef image; public final long view; - public VImageView(VContext ctx, VImage image) { + protected VImageView(VContext ctx, final VRef image) { this.ctx = ctx; - this.image = image; + this.image = image.addRef(); - int imageViewType = switch (image.dimensions) { + int imageViewType = switch (image.get().dimensions) { case 1 -> VK_IMAGE_VIEW_TYPE_1D; case 2 -> VK_IMAGE_VIEW_TYPE_2D; case 3 -> VK_IMAGE_VIEW_TYPE_3D; @@ -31,8 +32,8 @@ public VImageView(VContext ctx, VImage image) { var vci = VkImageViewCreateInfo.calloc(stack) .sType$Default() .viewType(imageViewType) - .format(image.format) - .image(image.image()); + .format(image.get().format) + .image(image.get().image()); vci.subresourceRange() .aspectMask(VK_IMAGE_ASPECT_COLOR_BIT) .layerCount(1) @@ -42,8 +43,15 @@ public VImageView(VContext ctx, VImage image) { } } - public void free() { - free0(); + public boolean isDerivedFrom(VImage image) { + return this.image.get().image() == image.image(); + } + + static public VRef create(VContext ctx, final VRef image) { + return new VRef<>(new VImageView(ctx, image)); + } + + protected void free() { vkDestroyImageView(ctx.device, view, null); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/other/VQueryPool.java b/src/main/java/me/cortex/vulkanite/lib/other/VQueryPool.java index 040b2bd..1f21484 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/VQueryPool.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/VQueryPool.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.other; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.cmd.VCmdBuff; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkCommandBuffer; @@ -13,10 +14,10 @@ import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; -public class VQueryPool extends TrackedResourceObject { +public class VQueryPool extends VObject { public final long pool; private final VkDevice device; - public VQueryPool(VkDevice device, int count, int type) { + private VQueryPool(VkDevice device, int count, int type) { this.device = device; try (MemoryStack stack = stackPush()) { LongBuffer pQueryPool = stack.mallocLong(1); @@ -31,12 +32,8 @@ public VQueryPool(VkDevice device, int count, int type) { } } - public void reset(VCmdBuff cmd, int first, int size) { - reset(cmd.buffer, first, size); - } - - public void reset(VkCommandBuffer cmd, int first, int size) { - vkCmdResetQueryPool(cmd, pool, first, size); + public static VRef create(VkDevice device, int count, int type) { + return new VRef<>(new VQueryPool(device, count, type)); } public long[] getResultsLong(int count) { @@ -53,8 +50,7 @@ public long[] getResultsLong(int start, int count, int flags) { } } - public void free() { - free0(); + protected void free() { vkDestroyQueryPool(device, pool, null); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/other/VSampler.java b/src/main/java/me/cortex/vulkanite/lib/other/VSampler.java index 076b700..20cfff9 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/VSampler.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/VSampler.java @@ -1,7 +1,8 @@ package me.cortex.vulkanite.lib.other; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VObject; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkSamplerCreateInfo; @@ -12,11 +13,11 @@ import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.vulkan.VK10.*; -public class VSampler extends TrackedResourceObject { +public final class VSampler extends VObject { private final VContext ctx; public final long sampler; - public VSampler(VContext context, Consumer setup) { + private VSampler(VContext context, Consumer setup) { this.ctx = context; try (MemoryStack stack = stackPush()) { LongBuffer pSampler = stack.mallocLong(1); @@ -30,9 +31,12 @@ public VSampler(VContext context, Consumer setup) { } } + public static VRef create(VContext context, Consumer setup) { + return new VRef<>(new VSampler(context, setup)); + } + @Override - public void free() { - free0(); + protected void free() { vkDestroySampler(ctx.device, sampler, null); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/other/VUtil.java b/src/main/java/me/cortex/vulkanite/lib/other/VUtil.java index 14654f7..a9fb816 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/VUtil.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/VUtil.java @@ -13,6 +13,7 @@ import static org.lwjgl.vulkan.KHRSwapchain.VK_ERROR_OUT_OF_DATE_KHR; import static org.lwjgl.vulkan.KHRSwapchain.VK_SUBOPTIMAL_KHR; import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK11.VK_ERROR_OUT_OF_POOL_MEMORY; public class VUtil { public static String translateVulkanResult(int result) { @@ -38,6 +39,8 @@ public static String translateVulkanResult(int result) { return "A host memory allocation has failed."; case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "A device memory allocation has failed."; + case VK_ERROR_OUT_OF_POOL_MEMORY: + return "A descriptor pool memory allocation has failed."; case VK_ERROR_INITIALIZATION_FAILED: return "Initialization of an object could not be completed for implementation-specific reasons."; case VK_ERROR_DEVICE_LOST: @@ -98,6 +101,15 @@ public static void _CHECK_GL_ERROR_() { } } + public static boolean _REPORT_GL_ERROR_() { + int e = glGetError(); + if (e != GL_NO_ERROR) { + System.err.println("Gl error: " + e); + return false; + } + return true; + } + public static int alignUp(int size, int alignment) { return (size + alignment - 1) & -alignment; diff --git a/src/main/java/me/cortex/vulkanite/lib/other/sync/SyncManager.java b/src/main/java/me/cortex/vulkanite/lib/other/sync/SyncManager.java index 8ce7816..9d7faa3 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/sync/SyncManager.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/sync/SyncManager.java @@ -1,7 +1,7 @@ package me.cortex.vulkanite.lib.other.sync; import me.cortex.vulkanite.client.Vulkanite; -import me.cortex.vulkanite.lib.memory.HandleDescriptorManger; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.PointerBuffer; import org.lwjgl.vulkan.*; @@ -13,8 +13,8 @@ import java.util.Map; import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; +import static me.cortex.vulkanite.lib.other.VUtil._CHECK_GL_ERROR_; import static org.lwjgl.opengl.EXTMemoryObjectFD.GL_HANDLE_TYPE_OPAQUE_FD_EXT; -import static org.lwjgl.opengl.EXTMemoryObjectFD.glImportMemoryFdEXT; import static org.lwjgl.opengl.EXTSemaphore.glGenSemaphoresEXT; import static org.lwjgl.opengl.EXTSemaphore.glIsSemaphoreEXT; import static org.lwjgl.opengl.EXTSemaphoreFD.glImportSemaphoreFdEXT; @@ -40,15 +40,15 @@ public SyncManager(VkDevice device) { this.device = device; } - public VFence createFence() { + public VRef createFence() { try (var stack = stackPush()) { LongBuffer res = stack.callocLong(1); _CHECK_(vkCreateFence(device, VkFenceCreateInfo.calloc(stack).sType$Default(), null, res)); - return new VFence(device, res.get(0)); + return VFence.create(device, res.get(0)); } } - private VGSemaphore createSharedBinarySemaphoreWin32() { + private VRef createSharedBinarySemaphoreWin32() { try (var stack = stackPush()) { LongBuffer res = stack.callocLong(1); _CHECK_(vkCreateSemaphore(device, @@ -71,20 +71,18 @@ private VGSemaphore createSharedBinarySemaphoreWin32() { if (pb.get(0)== 0) { throw new IllegalStateException(); } - HandleDescriptorManger.add(pb.get(0)); int glSemaphore = glGenSemaphoresEXT(); glImportSemaphoreWin32HandleEXT(glSemaphore, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, pb.get(0)); + _CHECK_GL_ERROR_(); if (!glIsSemaphoreEXT(glSemaphore)) throw new IllegalStateException(); - if (glGetError() != GL_NO_ERROR) - throw new IllegalStateException(); - return new VGSemaphore(device, semaphore, glSemaphore, pb.get(0)); + return VGSemaphore.create(device, semaphore, glSemaphore, pb.get(0)); } } - private VGSemaphore createSharedBinarySemaphoreFd() { + private VRef createSharedBinarySemaphoreFd() { try (var stack = stackPush()) { LongBuffer res = stack.callocLong(1); _CHECK_(vkCreateSemaphore(device, @@ -96,39 +94,40 @@ private VGSemaphore createSharedBinarySemaphoreFd() { null, res)); long semaphore = res.get(0); - IntBuffer fd = stack.callocInt(1); + IntBuffer fdPtr = stack.callocInt(1); _CHECK_(vkGetSemaphoreFdKHR(device, VkSemaphoreGetFdInfoKHR.calloc(stack) .sType$Default() .semaphore(semaphore) .handleType(EXTERNAL_SEMAPHORE_TYPE), - fd)); + fdPtr)); + + int fd = fdPtr.get(0); - if (fd.get(0)== 0) { + if (fd == 0) { throw new IllegalStateException(); } - HandleDescriptorManger.add(fd.get(0)); int glSemaphore = glGenSemaphoresEXT(); - glImportSemaphoreFdEXT(glSemaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd.get(0)); + glImportSemaphoreFdEXT(glSemaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd); + _CHECK_GL_ERROR_(); if (!glIsSemaphoreEXT(glSemaphore)) throw new IllegalStateException(); - if (glGetError() != GL_NO_ERROR) - throw new IllegalStateException(); - return new VGSemaphore(device, semaphore, glSemaphore, fd.get(0)); + fd = -1; + return VGSemaphore.create(device, semaphore, glSemaphore, fd); } } - public VGSemaphore createSharedBinarySemaphore() { + public VRef createSharedBinarySemaphore() { return Vulkanite.IS_WINDOWS?createSharedBinarySemaphoreWin32():createSharedBinarySemaphoreFd(); } - public VSemaphore createBinarySemaphore() { + public VRef createBinarySemaphore() { try (var stack = stackPush()) { LongBuffer res = stack.callocLong(1); _CHECK_(vkCreateSemaphore(device, VkSemaphoreCreateInfo.calloc(stack).sType$Default(), null, res)); - return new VSemaphore(device, res.get(0)); + return VSemaphore.create(device, res.get(0)); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/other/sync/VFence.java b/src/main/java/me/cortex/vulkanite/lib/other/sync/VFence.java index 518f8f7..2081e83 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/sync/VFence.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/sync/VFence.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.other.sync; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.Pointer; import org.lwjgl.vulkan.VkDevice; @@ -8,22 +9,26 @@ import static org.lwjgl.vulkan.VK10.vkDestroyFence; -public final class VFence extends TrackedResourceObject implements Pointer { +public final class VFence extends VObject implements Pointer { private final VkDevice device; private final long fence; - public VFence(VkDevice device, long fence) { + private VFence(VkDevice device, long fence) { this.device = device; this.fence = fence; } + static VRef create(VkDevice device, long fence) { + return new VRef<>(new VFence(device, fence)); + } + @Override public long address() { return fence; } - public void free() { - free0(); + @Override + protected void free() { vkDestroyFence(device, fence, null); } diff --git a/src/main/java/me/cortex/vulkanite/lib/other/sync/VGSemaphore.java b/src/main/java/me/cortex/vulkanite/lib/other/sync/VGSemaphore.java index 421398a..324690b 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/sync/VGSemaphore.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/sync/VGSemaphore.java @@ -1,7 +1,11 @@ package me.cortex.vulkanite.lib.other.sync; -import me.cortex.vulkanite.lib.memory.HandleDescriptorManger; -import me.cortex.vulkanite.lib.memory.MemoryManager; +import com.sun.jna.Pointer; +import com.sun.jna.platform.linux.LibC; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinNT; +import me.cortex.vulkanite.client.Vulkanite; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.vulkan.VkDevice; import static org.lwjgl.opengl.EXTSemaphore.*; @@ -10,16 +14,34 @@ public class VGSemaphore extends VSemaphore { public final int glSemaphore; private final long handleDescriptor; - public VGSemaphore(VkDevice device, long semaphore, int glSemaphore, long handleDescriptor) { + protected VGSemaphore(VkDevice device, long semaphore, int glSemaphore, long handleDescriptor) { super(device, semaphore); this.glSemaphore = glSemaphore; this.handleDescriptor = handleDescriptor; } + public static VRef create(VkDevice device, long semaphore, int glSemaphore, long handleDescriptor) { + return new VRef<>(new VGSemaphore(device, semaphore, glSemaphore, handleDescriptor)); + } + @Override - public void free() { - HandleDescriptorManger.close(handleDescriptor); - glDeleteSemaphoresEXT(glSemaphore); + protected void free() { + glDeleteSemaphoresEXT(this.glSemaphore); + if (Vulkanite.IS_WINDOWS) { + if (!Kernel32.INSTANCE.CloseHandle(new WinNT.HANDLE(new Pointer(handleDescriptor)))) { + int error = Kernel32.INSTANCE.GetLastError(); + System.err.println("STATE MIGHT BE BROKEN! Failed to close handle: " + error); + throw new IllegalStateException(); + } + } else { + int code = 0; + if (handleDescriptor != -1) { + if ((code = LibC.INSTANCE.close((int) handleDescriptor)) != 0) { + System.err.println("STATE MIGHT BE BROKEN! Failed to close FD: " + code); + throw new IllegalStateException(); + } + } + } super.free(); } diff --git a/src/main/java/me/cortex/vulkanite/lib/other/sync/VSemaphore.java b/src/main/java/me/cortex/vulkanite/lib/other/sync/VSemaphore.java index 7dd7b3b..653b106 100644 --- a/src/main/java/me/cortex/vulkanite/lib/other/sync/VSemaphore.java +++ b/src/main/java/me/cortex/vulkanite/lib/other/sync/VSemaphore.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.other.sync; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.Pointer; import org.lwjgl.vulkan.VkDevice; @@ -8,22 +9,25 @@ import static org.lwjgl.vulkan.VK10.vkDestroySemaphore; -public class VSemaphore extends TrackedResourceObject implements Pointer { +public class VSemaphore extends VObject implements Pointer { private final VkDevice device; private final long semaphore; - public VSemaphore(VkDevice device, long semaphore) { + protected VSemaphore(VkDevice device, long semaphore) { this.device = device; this.semaphore = semaphore; } + public static VRef create(VkDevice device, long semaphore) { + return new VRef<>(new VSemaphore(device, semaphore)); + } + @Override public long address() { return semaphore; } - public void free() { - free0(); + protected void free() { vkDestroySemaphore(device, semaphore, null); } diff --git a/src/main/java/me/cortex/vulkanite/lib/pipeline/ComputePipelineBuilder.java b/src/main/java/me/cortex/vulkanite/lib/pipeline/ComputePipelineBuilder.java index 97cb410..5c12461 100644 --- a/src/main/java/me/cortex/vulkanite/lib/pipeline/ComputePipelineBuilder.java +++ b/src/main/java/me/cortex/vulkanite/lib/pipeline/ComputePipelineBuilder.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.pipeline; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; import me.cortex.vulkanite.lib.shader.ShaderModule; import org.lwjgl.vulkan.*; @@ -19,8 +20,8 @@ public ComputePipelineBuilder() { } - Set layouts = new LinkedHashSet<>(); - public ComputePipelineBuilder addLayout(VDescriptorSetLayout layout) { + Set> layouts = new LinkedHashSet<>(); + public ComputePipelineBuilder addLayout(VRef layout) { layouts.add(layout); return this; } @@ -38,14 +39,14 @@ public void addPushConstantRange(int size, int offset) { pushConstants.add(new PushConstant(size, offset)); } - public VComputePipeline build(VContext context) { + public VRef build(VContext context) { try (var stack = stackPush()) { VkPipelineLayoutCreateInfo layoutCreateInfo = VkPipelineLayoutCreateInfo.calloc(stack) .sType$Default(); { //TODO: cleanup and add push constants - layoutCreateInfo.pSetLayouts(stack.longs(layouts.stream().mapToLong(a->a.layout).toArray())); + layoutCreateInfo.pSetLayouts(stack.longs(layouts.stream().mapToLong(a->a.get().layout).toArray())); } if (pushConstants.size() > 0) { @@ -71,7 +72,7 @@ public VComputePipeline build(VContext context) { .layout(pLayout.get(0)) .stage(shaderStage), null, pPipeline)); - return new VComputePipeline(context, pLayout.get(0), pPipeline.get(0)); + return new VRef<>(new VComputePipeline(context, pLayout.get(0), pPipeline.get(0))); } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/pipeline/RaytracePipelineBuilder.java b/src/main/java/me/cortex/vulkanite/lib/pipeline/RaytracePipelineBuilder.java index 3d24240..b7e88d1 100644 --- a/src/main/java/me/cortex/vulkanite/lib/pipeline/RaytracePipelineBuilder.java +++ b/src/main/java/me/cortex/vulkanite/lib/pipeline/RaytracePipelineBuilder.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.pipeline; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.shader.ShaderModule; @@ -58,20 +59,20 @@ public RaytracePipelineBuilder addCallable(ShaderModule callable) { return this; } - ArrayList layouts = new ArrayList<>(); - public RaytracePipelineBuilder addLayout(VDescriptorSetLayout layout) { + List> layouts = new ArrayList<>(); + public RaytracePipelineBuilder addLayout(VRef layout) { layouts.add(layout); return this; } //TODO: generate stb - public VRaytracePipeline build(VContext context, int maxDepth) { + public VRef build(VContext context, int maxDepth) { shaders.add(gen); ArrayList reflections = new ArrayList<>(); ShaderReflection reflection = null; for (var shader : shaders) { - reflections.add(shader.shader().getReflection()); + reflections.add(shader.shader().get().getReflection()); } try { reflection = ShaderReflection.mergeStages(reflections.toArray(ShaderReflection[]::new)); @@ -136,7 +137,7 @@ public VRaytracePipeline build(VContext context, int maxDepth) { { //TODO: cleanup and add push constants - layoutCreateInfo.pSetLayouts(stack.longs(layouts.stream().mapToLong(a->a.layout).toArray())); + layoutCreateInfo.pSetLayouts(stack.longs(layouts.stream().mapToLong(a->a.get().layout).toArray())); } LongBuffer pLayout = stack.mallocLong(1); @@ -183,12 +184,14 @@ public VRaytracePipeline build(VContext context, int maxDepth) { long aHandles = MemoryUtil.memAddress(handles); //TODO/FIXME: add alignment to gpu buffer - VBuffer sbtMap = context.memory.createBuffer(sbtSize, + VRef sbtMapRef = context.memory.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT); + VBuffer sbtMap = sbtMapRef.get(); + sbtMap.setDebugUtilsObjectName("SBT"); long ptr = sbtMap.map(); // Groups in order of RayGen, Miss Groups, Hit Groups, and callable @@ -214,14 +217,14 @@ public VRaytracePipeline build(VContext context, int maxDepth) { sbtMap.unmap(); sbtMap.flush(); - return new VRaytracePipeline(context, pPipeline.get(0), pLayout.get(0), sbtMap, + return new VRef<>(new VRaytracePipeline(context, pPipeline.get(0), pLayout.get(0), sbtMapRef, VkStridedDeviceAddressRegionKHR.calloc().set(sbtMap.deviceAddress() + rgenBase, handleSizeAligned, handleSizeAligned), VkStridedDeviceAddressRegionKHR.calloc().set(sbtMap.deviceAddress() + missGroupBase, handleSizeAligned, handleSizeAligned * missGroupCount), VkStridedDeviceAddressRegionKHR.calloc().set(sbtMap.deviceAddress() + hitGroupsBase, handleSizeAligned, handleSizeAligned * hitGroupsCount), VkStridedDeviceAddressRegionKHR.calloc().set(sbtMap.deviceAddress() + callGroupBase, handleSizeAligned, handleSizeAligned * callGroupCount), shaders, reflection - ); + )); } } } diff --git a/src/main/java/me/cortex/vulkanite/lib/pipeline/VComputePipeline.java b/src/main/java/me/cortex/vulkanite/lib/pipeline/VComputePipeline.java index 32c2e34..0439b6e 100644 --- a/src/main/java/me/cortex/vulkanite/lib/pipeline/VComputePipeline.java +++ b/src/main/java/me/cortex/vulkanite/lib/pipeline/VComputePipeline.java @@ -1,10 +1,10 @@ package me.cortex.vulkanite.lib.pipeline; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; import me.cortex.vulkanite.lib.base.VContext; -import me.cortex.vulkanite.lib.other.sync.VFence; +import me.cortex.vulkanite.lib.base.VObject; +import static org.lwjgl.vulkan.VK10.vkDestroyPipeline; -public class VComputePipeline extends TrackedResourceObject { +public class VComputePipeline extends VObject { private final VContext context; private final long pipeline; private final long layout; @@ -25,6 +25,6 @@ public long pipeline() { @Override public void free() { - + vkDestroyPipeline(context.device, pipeline, null); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/pipeline/VRaytracePipeline.java b/src/main/java/me/cortex/vulkanite/lib/pipeline/VRaytracePipeline.java index d1da4a8..fec99d8 100644 --- a/src/main/java/me/cortex/vulkanite/lib/pipeline/VRaytracePipeline.java +++ b/src/main/java/me/cortex/vulkanite/lib/pipeline/VRaytracePipeline.java @@ -1,7 +1,8 @@ package me.cortex.vulkanite.lib.pipeline; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VObject; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.cmd.VCmdBuff; import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.shader.ShaderModule; @@ -14,30 +15,30 @@ import static org.lwjgl.vulkan.KHRRayTracingPipeline.vkCmdTraceRaysKHR; import static org.lwjgl.vulkan.VK10.*; -public class VRaytracePipeline extends TrackedResourceObject { +public class VRaytracePipeline extends VObject { private final VContext context; - private final long pipeline; - private final long layout; - private final VBuffer shader_binding_table; - private final VkStridedDeviceAddressRegionKHR gen; - private final VkStridedDeviceAddressRegionKHR miss; - private final VkStridedDeviceAddressRegionKHR hit; - private final VkStridedDeviceAddressRegionKHR callable; + public final long pipeline; + public final long layout; + @SuppressWarnings("FieldCanBeLocal") + private final VRef shader_binding_table; + public final VkStridedDeviceAddressRegionKHR gen; + public final VkStridedDeviceAddressRegionKHR miss; + public final VkStridedDeviceAddressRegionKHR hit; + public final VkStridedDeviceAddressRegionKHR callable; private final Set shadersUsed; public final ShaderReflection reflection; - VRaytracePipeline(VContext context, long pipeline, long layout, VBuffer sbtMap, + VRaytracePipeline(VContext context, long pipeline, long layout, final VRef sbtMap, VkStridedDeviceAddressRegionKHR raygen, VkStridedDeviceAddressRegionKHR miss, VkStridedDeviceAddressRegionKHR hit, VkStridedDeviceAddressRegionKHR callable, Set shadersUsed, ShaderReflection reflection) { - this.context = context; this.pipeline = pipeline; this.layout = layout; - this.shader_binding_table = sbtMap; + this.shader_binding_table = sbtMap.addRef(); this.gen = raygen; this.miss = miss; this.hit = hit; @@ -46,22 +47,8 @@ public class VRaytracePipeline extends TrackedResourceObject { this.reflection = reflection; } - public void bind(VCmdBuff cmd) { - vkCmdBindPipeline(cmd.buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline); - } - - public void trace(VCmdBuff cmd, int width, int height, int depth) { - vkCmdTraceRaysKHR(cmd.buffer, gen, miss, hit, callable, width, height, depth); - } - - public void bindDSet(VCmdBuff cmd, long... descs) { - vkCmdBindDescriptorSets(cmd.buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, layout, 0, descs, null); - } - - public void free() { - free0(); + protected void free() { vkDestroyPipeline(context.device, pipeline, null); - shader_binding_table.free(); gen.free(); miss.free(); hit.free(); diff --git a/src/main/java/me/cortex/vulkanite/lib/shader/ShaderModule.java b/src/main/java/me/cortex/vulkanite/lib/shader/ShaderModule.java index 7b70788..f72ed53 100644 --- a/src/main/java/me/cortex/vulkanite/lib/shader/ShaderModule.java +++ b/src/main/java/me/cortex/vulkanite/lib/shader/ShaderModule.java @@ -1,14 +1,15 @@ package me.cortex.vulkanite.lib.shader; +import me.cortex.vulkanite.lib.base.VRef; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkPipelineShaderStageCreateInfo; public record ShaderModule( - VShader shader, String name) { + VRef shader, String name) { public void setupStruct(MemoryStack stack, VkPipelineShaderStageCreateInfo struct) { struct.sType$Default() - .stage(shader.stage) - .module(shader.module) + .stage(shader.get().stage) + .module(shader.get().module) .pName(stack.UTF8(name)); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/shader/VShader.java b/src/main/java/me/cortex/vulkanite/lib/shader/VShader.java index 47ed7ca..546259e 100644 --- a/src/main/java/me/cortex/vulkanite/lib/shader/VShader.java +++ b/src/main/java/me/cortex/vulkanite/lib/shader/VShader.java @@ -1,7 +1,8 @@ package me.cortex.vulkanite.lib.shader; -import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VObject; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.shader.reflection.ShaderReflection; import org.lwjgl.vulkan.VkShaderModuleCreateInfo; @@ -14,7 +15,7 @@ import static org.lwjgl.vulkan.KHRRayTracingPipeline.*; import static org.lwjgl.vulkan.VK10.*; -public class VShader extends TrackedResourceObject { +public class VShader extends VObject { private final VContext ctx; public final long module; public final int stage; @@ -24,7 +25,7 @@ public ShaderReflection getReflection() { return reflection; } - public VShader(VContext ctx, long module, int stage, ShaderReflection reflection) { + private VShader(VContext ctx, long module, int stage, ShaderReflection reflection) { this.ctx = ctx; this.module = module; this.stage = stage; @@ -36,10 +37,10 @@ public ShaderModule named() { } public ShaderModule named(String name) { - return new ShaderModule(this, name); + return new ShaderModule(new VRef<>(this), name); } - public static VShader compileLoad(VContext ctx, String source, int stage) { + public static VRef compileLoad(VContext ctx, String source, int stage) { try (var stack = stackPush()) { ByteBuffer code = ShaderCompiler.compileShader("shader", source, stage); @@ -50,13 +51,12 @@ public static VShader compileLoad(VContext ctx, String source, int stage) { .pCode(code); LongBuffer pShaderModule = stack.mallocLong(1); _CHECK_(vkCreateShaderModule(ctx.device, createInfo, null, pShaderModule)); - return new VShader(ctx, pShaderModule.get(0), stage, reflection); + return new VRef<>(new VShader(ctx, pShaderModule.get(0), stage, reflection)); } } @Override - public void free() { - free0(); + protected void free() { vkDestroyShaderModule(ctx.device, module, null); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java b/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java index 20612ae..e24a45f 100644 --- a/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java +++ b/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.lib.shader.reflection; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.descriptors.DescriptorSetLayoutBuilder; import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; import org.lwjgl.util.spvc.SpvcReflectedResource; @@ -195,13 +196,13 @@ public static ShaderReflection mergeStages(ShaderReflection ...stages) { return out; } - public List buildSetLayouts(VContext context) { + public List> buildSetLayouts(VContext context) { // TODO: Pick a better number, somehow return buildSetLayouts(context, 65536); } - private List layouts = new ArrayList<>(); - public List buildSetLayouts(VContext context, int runtimeSizedArrayMaxSize) { + private List> layouts = new ArrayList<>(); + public List> buildSetLayouts(VContext context, int runtimeSizedArrayMaxSize) { freeLayouts(); layouts = new ArrayList<>(); for (var set : sets) { @@ -231,14 +232,12 @@ public List buildSetLayouts(VContext context, int runtimeS return layouts; } - public final List getLayouts() { + public final List> getLayouts() { return layouts; } public void freeLayouts() { - for (var l : layouts) { - l.free(); - } + layouts.clear(); } private static void _CHECK_(int status) { diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCelestialUniforms.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCelestialUniforms.java index 660ab9e..f810a3f 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCelestialUniforms.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCelestialUniforms.java @@ -1,6 +1,6 @@ package me.cortex.vulkanite.mixin.iris; -import net.coderbot.iris.uniforms.CelestialUniforms; +import net.irisshaders.iris.uniforms.CelestialUniforms; import org.joml.Vector4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCommonUniforms.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCommonUniforms.java index 4d07ce4..b7a4069 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCommonUniforms.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinCommonUniforms.java @@ -1,6 +1,6 @@ package me.cortex.vulkanite.mixin.iris; -import net.coderbot.iris.uniforms.CommonUniforms; +import net.irisshaders.iris.uniforms.CommonUniforms; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlResource.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlResource.java index 87e4d0f..b6cb42c 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlResource.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlResource.java @@ -3,10 +3,9 @@ import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IRenderTargetVkGetter; import me.cortex.vulkanite.lib.memory.VGImage; -import net.coderbot.iris.gl.GlResource; -import net.coderbot.iris.gl.texture.InternalTextureFormat; -import net.coderbot.iris.gl.texture.PixelFormat; -import net.coderbot.iris.rendertarget.RenderTarget; +import net.irisshaders.iris.gl.GlResource; +import net.irisshaders.iris.gl.texture.InternalTextureFormat; +import net.irisshaders.iris.gl.texture.PixelFormat; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlTexture.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlTexture.java index fc3d051..90eb669 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlTexture.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinGlTexture.java @@ -3,13 +3,14 @@ import com.mojang.blaze3d.systems.RenderSystem; import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGImage; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; import me.cortex.vulkanite.lib.other.FormatConverter; -import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.gl.texture.GlTexture; -import net.coderbot.iris.gl.texture.InternalTextureFormat; -import net.coderbot.iris.gl.texture.TextureType; -import net.coderbot.iris.shaderpack.texture.TextureFilteringData; +import net.irisshaders.iris.gl.IrisRenderSystem; +import net.irisshaders.iris.gl.texture.GlTexture; +import net.irisshaders.iris.gl.texture.InternalTextureFormat; +import net.irisshaders.iris.gl.texture.TextureType; +import net.irisshaders.iris.shaderpack.texture.TextureFilteringData; import org.lwjgl.opengl.GL30; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; @@ -17,19 +18,20 @@ import java.nio.ByteBuffer; +import static me.cortex.vulkanite.lib.other.VUtil._CHECK_GL_ERROR_; import static org.lwjgl.opengl.GL11C.*; import static org.lwjgl.vulkan.VK10.*; @Mixin(value = GlTexture.class, remap = false) public abstract class MixinGlTexture extends MixinGlResource implements IVGImage { - @Unique private VGImage sharedImage; + @Unique private VRef sharedImage; @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_genTexture()I")) private static int redirectGen() { return -1; } - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/gl/texture/GlTexture;getGlId()I", ordinal = 0)) + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/gl/texture/GlTexture;getGlId()I", ordinal = 0)) private int redirectTextureCreation(GlTexture instance, TextureType target, int sizeX, int sizeY, int sizeZ, int internalFormat, int format, int pixelType, byte[] pixels, TextureFilteringData filteringData) { // Before getting the texture id, create the texture that wasn't created earlier @@ -52,17 +54,18 @@ private int redirectTextureCreation(GlTexture instance, TextureType target, int VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); + sharedImage.get().setDebugUtilsObjectName("GlTexture"); Vulkanite.INSTANCE.getCtx().cmd.executeWait(cmdbuf -> { - cmdbuf.encodeImageTransition(sharedImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(sharedImage.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); }); - this.setGlId(sharedImage.glId); + this.setGlId(sharedImage.get().glId); - return sharedImage.glId; + return sharedImage.get().glId; } - @Redirect(method="", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/gl/texture/TextureType;apply(IIIIIIILjava/nio/ByteBuffer;)V")) + @Redirect(method="", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/gl/texture/TextureType;apply(IIIIIIILjava/nio/ByteBuffer;)V")) private void redirectUpload(TextureType instance, int glId, int width, int height, int depth, int internalFormat, int format, int pixelType, ByteBuffer data) { int target = instance.getGlType(); @@ -80,15 +83,15 @@ private void redirectUpload(TextureType instance, int glId, int width, int heigh GL30.glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth, format, pixelType, data); break; } + _CHECK_GL_ERROR_(); } @Overwrite protected void destroyInternal(){ - glFinish(); - sharedImage.free(); + sharedImage = null; } - public VGImage getVGImage() { - return sharedImage; + public VRef getVGImage() { + return sharedImage == null ? null : sharedImage.addRef(); } } diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinIrisRenderingPipeline.java similarity index 71% rename from src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java rename to src/main/java/me/cortex/vulkanite/mixin/iris/MixinIrisRenderingPipeline.java index a711fe2..adf5a72 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNewWorldRenderingPipeline.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinIrisRenderingPipeline.java @@ -6,21 +6,20 @@ import me.cortex.vulkanite.client.rendering.VulkanPipeline; import me.cortex.vulkanite.compat.*; import me.cortex.vulkanite.lib.base.VContext; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; -import net.coderbot.iris.gl.buffer.ShaderStorageBuffer; -import net.coderbot.iris.gl.texture.TextureAccess; -import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder; -import net.coderbot.iris.gl.uniform.DynamicUniformHolder; -import net.coderbot.iris.mixin.LevelRendererAccessor; -import net.coderbot.iris.pipeline.CustomTextureManager; -import net.coderbot.iris.pipeline.newshader.NewWorldRenderingPipeline; -import net.coderbot.iris.rendertarget.RenderTargets; -import net.coderbot.iris.shaderpack.ProgramSet; -import net.coderbot.iris.shaderpack.texture.TextureStage; -import net.coderbot.iris.uniforms.CelestialUniforms; -import net.coderbot.iris.uniforms.custom.CustomUniforms; +import net.irisshaders.iris.gl.buffer.ShaderStorageBuffer; +import net.irisshaders.iris.gl.texture.TextureAccess; +import net.irisshaders.iris.gl.buffer.ShaderStorageBufferHolder; +import net.irisshaders.iris.mixin.LevelRendererAccessor; +import net.irisshaders.iris.pipeline.CustomTextureManager; +import net.irisshaders.iris.pipeline.IrisRenderingPipeline; +import net.irisshaders.iris.shaderpack.programs.ProgramSet; +import net.irisshaders.iris.shaderpack.texture.TextureStage; +import net.irisshaders.iris.targets.RenderTargets; +import net.irisshaders.iris.uniforms.CelestialUniforms; import net.minecraft.client.render.Camera; -import org.jetbrains.annotations.Nullable; +import net.minecraft.client.MinecraftClient; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -28,13 +27,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -@Mixin(value = NewWorldRenderingPipeline.class, remap = false) -public class MixinNewWorldRenderingPipeline { +@Mixin(value = IrisRenderingPipeline.class, remap = false) +public class MixinIrisRenderingPipeline { @Shadow @Final private RenderTargets renderTargets; @Shadow @Final private CustomTextureManager customTextureManager; @@ -46,7 +46,7 @@ public class MixinNewWorldRenderingPipeline { @Unique private VulkanPipeline pipeline; @Unique - private VGImage[] getCustomTextures() { + private List> getCustomTextures() { Object2ObjectMap texturesBinary = customTextureManager.getIrisCustomTextures(); Object2ObjectMap texturesPNGs = customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW); @@ -58,7 +58,7 @@ private VGImage[] getCustomTextures() { return entryList.stream() .map(entry -> ((IVGImage) entry.getValue()).getVGImage()) - .toArray(VGImage[]::new); + .toList(); } @Inject(method = "", at = @At("TAIL")) @@ -77,13 +77,16 @@ private void injectRTShader(ProgramSet set, CallbackInfo ci) { @Inject(method = "renderShadows", at = @At("TAIL")) private void renderShadows(LevelRendererAccessor par1, Camera par2, CallbackInfo ci) { + var prof = MinecraftClient.getInstance().getProfiler(); + prof.push("vulkanite_render_shadows"); + ShaderStorageBuffer[] buffers = new ShaderStorageBuffer[0]; if(shaderStorageBufferHolder != null) { buffers = ((ShaderStorageBufferHolderAccessor)shaderStorageBufferHolder).getBuffers(); } - List outImgs = new ArrayList<>(); + List> outImgs = new ArrayList<>(); for (int i = 0; i < renderTargets.getRenderTargetCount(); i++) { outImgs.add(((IRenderTargetVkGetter)renderTargets.getOrCreate(i)).getMain()); } @@ -91,18 +94,27 @@ private void renderShadows(LevelRendererAccessor par1, Camera par2, CallbackInfo MixinCelestialUniforms celestialUniforms = (MixinCelestialUniforms)(Object) new CelestialUniforms(this.sunPathRotation); pipeline.renderPostShadows(outImgs, par2, buffers, celestialUniforms); + + prof.pop(); + } + + @Inject(method = "shouldDisableVanillaEntityShadows", at = @At("HEAD"), cancellable = true) + private void shouldDisableVanillaEntityShadows(CallbackInfoReturnable ci) { + if (pipeline != null) { + ci.setReturnValue(true); + } } @Inject(method = "destroyShaders", at = @At("TAIL")) private void destory(CallbackInfo ci) { + if (ctx == null) return; + ctx.cmd.waitQueueIdle(0); - if (rtShaderPasses != null) { - for (var pass : rtShaderPasses) { - pass.delete(); - } - } pipeline.destory(); rtShaderPasses = null; pipeline = null; + + // Force a GC, collect all dangling resources + System.gc(); } } diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNativeImageBackedTexture.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNativeImageBackedTexture.java index 01f0eb0..941d698 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNativeImageBackedTexture.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinNativeImageBackedTexture.java @@ -5,9 +5,10 @@ import com.mojang.blaze3d.systems.RenderSystem; import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGImage; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.mixin.minecraft.MixinAbstractTexture; -import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.rendertarget.NativeImageBackedCustomTexture; +import net.irisshaders.iris.gl.IrisRenderSystem; +import net.irisshaders.iris.targets.backed.NativeImageBackedCustomTexture; import net.minecraft.client.texture.AbstractTexture; import net.minecraft.client.texture.NativeImage; import net.minecraft.client.texture.NativeImageBackedTexture; @@ -38,7 +39,6 @@ private void redirectGen(int id, int width, int height) { } if (getVGImage() != null) { System.err.println("Vulkan image already allocated, releasing"); - Vulkanite.INSTANCE.addSyncedCallback(getVGImage()::free); setVGImage(null); } @@ -50,12 +50,13 @@ private void redirectGen(int id, int width, int height) { GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + img.get().setDebugUtilsObjectName("NativeImageBackedTexture"); setVGImage(img); Vulkanite.INSTANCE.getCtx().cmd.executeWait(cmdbuf -> { - cmdbuf.encodeImageTransition(img, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(img.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); }); - GlStateManager._bindTexture(img.glId); + GlStateManager._bindTexture(img.get().glId); } } diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPBRAtlasTexture.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPBRAtlasTexture.java index 83873d6..579538b 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPBRAtlasTexture.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPBRAtlasTexture.java @@ -3,7 +3,8 @@ import com.mojang.blaze3d.platform.GlStateManager; import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGImage; -import net.coderbot.iris.texture.pbr.PBRAtlasTexture; +import me.cortex.vulkanite.lib.base.VRef; +import net.irisshaders.iris.texture.pbr.PBRAtlasTexture; import net.minecraft.client.texture.AbstractTexture; import net.minecraft.client.texture.SpriteAtlasTexture; import org.spongepowered.asm.mixin.Mixin; @@ -20,7 +21,6 @@ public abstract class MixinPBRAtlasTexture extends AbstractTexture implements IV private void redirect(int id, int maxLevel, int width, int height) { if (getVGImage() != null) { System.err.println("Vulkan image already allocated, releasing"); - Vulkanite.INSTANCE.addSyncedCallback(getVGImage()::free); setVGImage(null); } @@ -36,10 +36,11 @@ private void redirect(int id, int maxLevel, int width, int height) { GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + img.get().setDebugUtilsObjectName("PBRAtlasTexture"); setVGImage(img); Vulkanite.INSTANCE.getCtx().cmd.executeWait(cmdbuf -> { - cmdbuf.encodeImageTransition(img, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(img.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); }); diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPackRenderTargetDirectives.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPackRenderTargetDirectives.java index 81608b4..e5c70f8 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPackRenderTargetDirectives.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinPackRenderTargetDirectives.java @@ -1,7 +1,7 @@ package me.cortex.vulkanite.mixin.iris; import com.google.common.collect.ImmutableSet; -import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import net.irisshaders.iris.shaderpack.properties.PackRenderTargetDirectives; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinProgramSet.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinProgramSet.java index f301105..618032d 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinProgramSet.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinProgramSet.java @@ -2,11 +2,10 @@ import me.cortex.vulkanite.compat.IGetRaytracingSource; import me.cortex.vulkanite.compat.RaytracingShaderSource; -import net.coderbot.iris.shaderpack.ProgramSet; -import net.coderbot.iris.shaderpack.ProgramSource; -import net.coderbot.iris.shaderpack.ShaderPack; -import net.coderbot.iris.shaderpack.ShaderProperties; -import net.coderbot.iris.shaderpack.include.AbsolutePackPath; +import net.irisshaders.iris.shaderpack.ShaderPack; +import net.irisshaders.iris.shaderpack.include.AbsolutePackPath; +import net.irisshaders.iris.shaderpack.programs.ProgramSet; +import net.irisshaders.iris.shaderpack.properties.ShaderProperties; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinRenderTarget.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinRenderTarget.java index bc750f7..5377830 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinRenderTarget.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinRenderTarget.java @@ -2,11 +2,12 @@ import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IRenderTargetVkGetter; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; import me.cortex.vulkanite.lib.other.FormatConverter; -import net.coderbot.iris.gl.texture.InternalTextureFormat; -import net.coderbot.iris.gl.texture.PixelFormat; -import net.coderbot.iris.rendertarget.RenderTarget; +import net.irisshaders.iris.gl.texture.InternalTextureFormat; +import net.irisshaders.iris.gl.texture.PixelFormat; +import net.irisshaders.iris.targets.RenderTarget; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -24,42 +25,38 @@ public abstract class MixinRenderTarget implements IRenderTargetVkGetter { @Shadow protected abstract void setupTexture(int i, int i1, int i2, boolean b); - @Unique private VGImage vgMainTexture; - @Unique private VGImage vgAltTexture; + @Unique private VRef vgMainTexture; + @Unique private VRef vgAltTexture; @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_genTextures([I)V")) private void redirectGen(int[] textures) { } - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/rendertarget/RenderTarget;setupTexture(IIIZ)V", ordinal = 0)) + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/targets/RenderTarget;setupTexture(IIIZ)V", ordinal = 0)) private void redirectMain(RenderTarget instance, int id, int width, int height, boolean allowsLinear) { setupTextures(width, height, allowsLinear); } - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/rendertarget/RenderTarget;setupTexture(IIIZ)V", ordinal = 1)) + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/targets/RenderTarget;setupTexture(IIIZ)V", ordinal = 1)) private void redirectAlt(RenderTarget instance, int id, int width, int height, boolean allowsLinear) {} - @Redirect(method = "setupTexture", at = @At(value = "INVOKE",target = "Lnet/coderbot/iris/rendertarget/RenderTarget;resizeTexture(III)V")) + @Redirect(method = "setupTexture", at = @At(value = "INVOKE",target = "Lnet/irisshaders/iris/targets/RenderTarget;resizeTexture(III)V")) private void redirectResize(RenderTarget instance, int t, int w, int h) {} @Overwrite public int getMainTexture() { - return vgMainTexture.glId; + return vgMainTexture.get().glId; } @Overwrite public int getAltTexture() { - return vgAltTexture.glId; + return vgAltTexture.get().glId; } @Overwrite public void resize(int width, int height) { glFinish(); - //TODO: block the gpu fully before deleting and resizing the textures - vgMainTexture.free(); - vgAltTexture.free(); - setupTextures(width, height, !internalFormat.getPixelFormat().isInteger()); } @@ -73,9 +70,11 @@ private void setupTextures(int width, int height, boolean allowsLinear) { vgMainTexture = ctx.memory.createSharedImage(width, height, 1, vkfmt, glfmt, VK_IMAGE_USAGE_STORAGE_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vgAltTexture = ctx.memory.createSharedImage(width, height, 1, vkfmt, glfmt, VK_IMAGE_USAGE_STORAGE_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vgMainTexture.get().setDebugUtilsObjectName("RenderTarget Main"); + vgAltTexture.get().setDebugUtilsObjectName("RenderTarget Alt"); Vulkanite.INSTANCE.getCtx().cmd.executeWait(cmdbuf -> { - cmdbuf.encodeImageTransition(vgMainTexture, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); - cmdbuf.encodeImageTransition(vgAltTexture, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(vgMainTexture.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(vgAltTexture.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); }); setupTexture(getMainTexture(), width, height, allowsLinear); @@ -84,17 +83,17 @@ private void setupTextures(int width, int height, boolean allowsLinear) { @Redirect(method = "destroy", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_deleteTextures([I)V")) private void redirectResize(int[] textures) { - glFinish(); +// glFinish(); //TODO: block the gpu fully before deleting and resizing the textures - vgMainTexture.free(); - vgAltTexture.free(); + vgMainTexture = null; + vgAltTexture = null; } - public VGImage getMain() { - return vgMainTexture; + public VRef getMain() { + return vgMainTexture.addRef(); } - public VGImage getAlt() { - return vgAltTexture; + public VRef getAlt() { + return vgAltTexture.addRef(); } } diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderPackSourceNames.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderPackSourceNames.java index 14b6d02..f75a4df 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderPackSourceNames.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderPackSourceNames.java @@ -1,7 +1,7 @@ package me.cortex.vulkanite.mixin.iris; import com.google.common.collect.ImmutableList; -import net.coderbot.iris.shaderpack.include.ShaderPackSourceNames; +import net.irisshaders.iris.shaderpack.include.ShaderPackSourceNames; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBuffer.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBuffer.java index 2c308ce..2ba5ba1 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBuffer.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBuffer.java @@ -2,9 +2,10 @@ import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGBuffer; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGBuffer; -import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.gl.buffer.ShaderStorageBuffer; +import net.irisshaders.iris.gl.IrisRenderSystem; +import net.irisshaders.iris.gl.buffer.ShaderStorageBuffer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -18,27 +19,27 @@ public class MixinShaderStorageBuffer implements IVGBuffer { @Shadow protected int id; @Unique - private VGBuffer vkBuffer; + private VRef vkBuffer; - public VGBuffer getBuffer() { - return vkBuffer; + public VRef getBuffer() { + return vkBuffer == null ? null : vkBuffer.addRef(); } - public void setBuffer(VGBuffer buffer) { + public void setBuffer(VRef buffer) { if (vkBuffer != null && buffer != null) { throw new IllegalStateException("Override buffer not null"); } this.vkBuffer = buffer; if (buffer != null) { glDeleteBuffers(id); - id = vkBuffer.glId; + id = vkBuffer.get().glId; } } - @Redirect(method = "destroy", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/gl/IrisRenderSystem;deleteBuffers(I)V")) + @Redirect(method = "destroy", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/gl/IrisRenderSystem;deleteBuffers(I)V")) private void redirectDelete(int id) { if (vkBuffer != null) { - Vulkanite.INSTANCE.addSyncedCallback(vkBuffer::free); + vkBuffer = null; } else { IrisRenderSystem.deleteBuffers(id); } diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBufferHolder.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBufferHolder.java index 65e8ee4..f0027fd 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBufferHolder.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinShaderStorageBufferHolder.java @@ -3,11 +3,12 @@ import com.mojang.blaze3d.platform.GlStateManager; import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGBuffer; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGBuffer; -import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.gl.buffer.ShaderStorageBuffer; -import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder; -import net.coderbot.iris.gl.buffer.ShaderStorageInfo; +import net.irisshaders.iris.gl.IrisRenderSystem; +import net.irisshaders.iris.gl.buffer.ShaderStorageBuffer; +import net.irisshaders.iris.gl.buffer.ShaderStorageBufferHolder; +import net.irisshaders.iris.gl.buffer.ShaderStorageInfo; import org.lwjgl.opengl.GL43C; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -21,22 +22,22 @@ public class MixinShaderStorageBufferHolder { @Unique private ShaderStorageInfo storageInfo; - @Redirect(method = "lambda$new$0", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/gl/buffer/ShaderStorageInfo;relative()Z")) + @Redirect(method = "lambda$new$0", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/gl/buffer/ShaderStorageInfo;relative()Z")) private boolean alwaysReturnTrue(ShaderStorageInfo instance) { this.storageInfo = instance; return true; } - private static VGBuffer alloc(int size) { + private static VRef alloc(int size) { return Vulkanite.INSTANCE.getCtx().memory.createSharedBuffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); } - @Redirect(method = "lambda$new$0", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/gl/buffer/ShaderStorageBuffer;resizeIfRelative(II)V")) + @Redirect(method = "lambda$new$0", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/gl/buffer/ShaderStorageBuffer;resizeIfRelative(II)V")) private void redirectSizeAllocation(ShaderStorageBuffer instance, int width, int height) { if (storageInfo.relative()) { instance.resizeIfRelative(width, height); } else { - ((IVGBuffer)instance).setBuffer(alloc(storageInfo.size())); + ((IVGBuffer)instance).setBuffer(alloc((int)storageInfo.size())); GlStateManager._glBindBuffer(GL43C.GL_SHADER_STORAGE_BUFFER, instance.getId()); IrisRenderSystem.clearBufferSubData(GL43C.GL_SHADER_STORAGE_BUFFER, GL43C.GL_R8, 0, storageInfo.size(), GL43C.GL_RED, GL43C.GL_BYTE, new int[] {0}); IrisRenderSystem.bindBufferBase(GL43C.GL_SHADER_STORAGE_BUFFER, instance.getIndex(), instance.getId()); diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinStandardMacros.java b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinStandardMacros.java index 4b51cd1..a22d2fa 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/MixinStandardMacros.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/MixinStandardMacros.java @@ -1,7 +1,7 @@ package me.cortex.vulkanite.mixin.iris; -import net.coderbot.iris.gl.shader.StandardMacros; -import net.coderbot.iris.shaderpack.StringPair; +import net.irisshaders.iris.gl.shader.StandardMacros; +import net.irisshaders.iris.helpers.StringPair; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -12,7 +12,7 @@ @Mixin(value = StandardMacros.class, remap = false) public class MixinStandardMacros { - @Inject(method = "createStandardEnvironmentDefines", at = @At(value = "INVOKE", target = "Lnet/coderbot/iris/gl/shader/StandardMacros;define(Ljava/util/List;Ljava/lang/String;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) + @Inject(method = "createStandardEnvironmentDefines", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/gl/shader/StandardMacros;define(Ljava/util/List;Ljava/lang/String;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) private static void injectVulkaniteDefine(CallbackInfoReturnable> cir, ArrayList defines) { defines.add(new StringPair("VULKANITE", " ")); } diff --git a/src/main/java/me/cortex/vulkanite/mixin/iris/ShaderStorageBufferHolderAccessor.java b/src/main/java/me/cortex/vulkanite/mixin/iris/ShaderStorageBufferHolderAccessor.java index 5d78387..ccba5a1 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/iris/ShaderStorageBufferHolderAccessor.java +++ b/src/main/java/me/cortex/vulkanite/mixin/iris/ShaderStorageBufferHolderAccessor.java @@ -1,7 +1,7 @@ package me.cortex.vulkanite.mixin.iris; -import net.coderbot.iris.gl.buffer.ShaderStorageBuffer; -import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder; +import net.irisshaders.iris.gl.buffer.ShaderStorageBuffer; +import net.irisshaders.iris.gl.buffer.ShaderStorageBufferHolder; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinAbstractTexture.java b/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinAbstractTexture.java index 35c04e2..0d4f5d8 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinAbstractTexture.java +++ b/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinAbstractTexture.java @@ -2,6 +2,7 @@ import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGImage; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; import net.minecraft.client.texture.AbstractTexture; import org.spongepowered.asm.mixin.Mixin; @@ -15,16 +16,16 @@ @Mixin(AbstractTexture.class) public class MixinAbstractTexture implements IVGImage { @Shadow protected int glId; - @Unique private VGImage vgImage; + @Unique private VRef vgImage; @Override - public void setVGImage(VGImage image) { + public void setVGImage(VRef image) { this.vgImage = image; } @Override - public VGImage getVGImage() { - return vgImage; + public VRef getVGImage() { + return vgImage == null ? null : vgImage; } @Inject(method = "getGlId", at = @At("HEAD"), cancellable = true) @@ -33,7 +34,7 @@ private void redirectGetId(CallbackInfoReturnable cir) { if (glId != -1) { throw new IllegalStateException("glId != -1 while VGImage is set"); } - cir.setReturnValue(vgImage.glId); + cir.setReturnValue(vgImage.get().glId); cir.cancel(); } } @@ -41,7 +42,6 @@ private void redirectGetId(CallbackInfoReturnable cir) { @Inject(method = "clearGlId", at = @At("HEAD"), cancellable = true) private void redirectClear(CallbackInfo ci) { if (vgImage != null) { - Vulkanite.INSTANCE.addSyncedCallback(vgImage::free); vgImage = null; glId = -1; ci.cancel(); diff --git a/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinResourceTexture.java b/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinResourceTexture.java index 2c8fc53..87a0f02 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinResourceTexture.java +++ b/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinResourceTexture.java @@ -5,6 +5,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGImage; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGImage; import net.minecraft.client.texture.AbstractTexture; import net.minecraft.client.texture.ResourceTexture; @@ -31,7 +32,6 @@ private void redirect(int id, int maxLevel, int width, int height) { RenderSystem.assertOnRenderThreadOrInit(); if (getVGImage() != null) { System.err.println("Vulkan image already allocated, releasing"); - Vulkanite.INSTANCE.addSyncedCallback(getVGImage()::free); setVGImage(null); } @@ -50,7 +50,7 @@ private void redirect(int id, int maxLevel, int width, int height) { setVGImage(img); Vulkanite.INSTANCE.getCtx().cmd.executeWait(cmdbuf -> { - cmdbuf.encodeImageTransition(img, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(img.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); }); GlStateManager._bindTexture(getGlId()); diff --git a/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinSpriteAtlasTexture.java b/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinSpriteAtlasTexture.java index 0095863..dd79b18 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinSpriteAtlasTexture.java +++ b/src/main/java/me/cortex/vulkanite/mixin/minecraft/MixinSpriteAtlasTexture.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.platform.GlStateManager; import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.compat.IVGImage; +import me.cortex.vulkanite.lib.base.VRef; import net.minecraft.client.texture.AbstractTexture; import net.minecraft.client.texture.SpriteAtlasTexture; import org.spongepowered.asm.mixin.Mixin; @@ -19,7 +20,6 @@ public abstract class MixinSpriteAtlasTexture extends AbstractTexture implements private void redirect(int id, int maxLevel, int width, int height) { if (getVGImage() != null) { System.err.println("Vulkan image already allocated, releasing"); - Vulkanite.INSTANCE.addSyncedCallback(getVGImage()::free); setVGImage(null); } @@ -35,10 +35,11 @@ private void redirect(int id, int maxLevel, int width, int height) { GL_RGBA8, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + img.get().setDebugUtilsObjectName("RenderTarget MainSpriteAtlasTexture"); setVGImage(img); Vulkanite.INSTANCE.getCtx().cmd.executeWait(cmdbuf -> { - cmdbuf.encodeImageTransition(img, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); + cmdbuf.encodeImageTransition(new VRef<>(img.get()), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_REMAINING_MIP_LEVELS); }); diff --git a/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinGLRenderDevice.java b/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinGLRenderDevice.java index 4627158..aab20dc 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinGLRenderDevice.java +++ b/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinGLRenderDevice.java @@ -13,7 +13,8 @@ public class MixinGLRenderDevice { @Inject(method = "deleteBuffer", at = @At("HEAD"), cancellable = true) private void redirectDelete(GlBuffer buffer, CallbackInfo ci) { if (buffer instanceof IVGBuffer vkBuffer && vkBuffer.getBuffer() != null) { - Vulkanite.INSTANCE.addSyncedCallback(vkBuffer.getBuffer()::free); + vkBuffer.getBuffer().close(); + vkBuffer.setBuffer(null); ci.cancel(); } } diff --git a/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinMutableBuffer.java b/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinMutableBuffer.java index 6ac8517..e3ffe75 100644 --- a/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinMutableBuffer.java +++ b/src/main/java/me/cortex/vulkanite/mixin/sodium/gl/MixinMutableBuffer.java @@ -1,6 +1,7 @@ package me.cortex.vulkanite.mixin.sodium.gl; import me.cortex.vulkanite.compat.IVGBuffer; +import me.cortex.vulkanite.lib.base.VRef; import me.cortex.vulkanite.lib.memory.VGBuffer; import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; @@ -11,20 +12,20 @@ @Mixin(value = GlMutableBuffer.class, remap = false) public class MixinMutableBuffer extends GlBuffer implements IVGBuffer { - @Unique private VGBuffer vkBuffer; + @Unique private VRef vkBuffer; - public VGBuffer getBuffer() { - return vkBuffer; + public VRef getBuffer() { + return vkBuffer == null ? null : vkBuffer.addRef(); } - public void setBuffer(VGBuffer buffer) { + public void setBuffer(VRef buffer) { if (vkBuffer != null && buffer != null) { throw new IllegalStateException("Override buffer not null"); } this.vkBuffer = buffer; if (buffer != null) { glDeleteBuffers(handle()); - setHandle(vkBuffer.glId); + setHandle(vkBuffer.get().glId); } } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 4cf63f7..84ccda1 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -15,7 +15,7 @@ ], "depends": { "fabricloader": ">=0.14.21", - "iris": "=1.6.9", - "sodium": "=0.5.3" + "iris": "=1.7.0", + "sodium": "=0.5.8" } } diff --git a/src/main/resources/vulkanite.mixins.json b/src/main/resources/vulkanite.mixins.json index 7934e92..36288e0 100644 --- a/src/main/resources/vulkanite.mixins.json +++ b/src/main/resources/vulkanite.mixins.json @@ -9,7 +9,7 @@ "iris.MixinGlResource", "iris.MixinGlTexture", "iris.MixinNativeImageBackedTexture", - "iris.MixinNewWorldRenderingPipeline", + "iris.MixinIrisRenderingPipeline", "iris.MixinPackRenderTargetDirectives", "iris.MixinPBRAtlasTexture", "iris.MixinProgramSet",