package com.mojang.blaze3d.vulkan; import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.buffers.GpuFence; import com.mojang.blaze3d.buffers.GpuBufferSlice.MappedView; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage.Format; import com.mojang.blaze3d.systems.CommandEncoderBackend; import com.mojang.blaze3d.systems.GpuQueryPool; import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderPassBackend; import com.mojang.blaze3d.systems.RenderPassDescriptor; import com.mojang.blaze3d.systems.RenderPassDescriptor.Attachment; import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.vulkan.VulkanQueue.Submission; import com.mojang.blaze3d.vulkan.checkpoints.CheckpointExtension; import java.nio.ByteBuffer; import java.nio.LongBuffer; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.OptionalDouble; import org.joml.Vector4fc; import org.jspecify.annotations.Nullable; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.lwjgl.vulkan.KHRDynamicRendering; import org.lwjgl.vulkan.KHRSynchronization2; import org.lwjgl.vulkan.VK12; import org.lwjgl.vulkan.VkBufferCopy; import org.lwjgl.vulkan.VkBufferImageCopy; import org.lwjgl.vulkan.VkClearAttachment; import org.lwjgl.vulkan.VkClearColorValue; import org.lwjgl.vulkan.VkClearDepthStencilValue; import org.lwjgl.vulkan.VkClearRect; import org.lwjgl.vulkan.VkClearValue; import org.lwjgl.vulkan.VkCommandBuffer; import org.lwjgl.vulkan.VkCommandBufferBeginInfo; import org.lwjgl.vulkan.VkDependencyInfo; import org.lwjgl.vulkan.VkImageCopy; import org.lwjgl.vulkan.VkImageSubresourceLayers; import org.lwjgl.vulkan.VkImageSubresourceRange; import org.lwjgl.vulkan.VkMemoryBarrier2; import org.lwjgl.vulkan.VkRect2D; import org.lwjgl.vulkan.VkRenderingAttachmentInfo; import org.lwjgl.vulkan.VkRenderingInfo; import org.lwjgl.vulkan.VkSemaphoreCreateInfo; import org.lwjgl.vulkan.VkSemaphoreTypeCreateInfo; import org.lwjgl.vulkan.VkSemaphoreWaitInfo; import org.lwjgl.vulkan.VkMemoryBarrier2.Buffer; public class VulkanCommandEncoder implements CommandEncoderBackend, Destroyable { public static final int MAX_SUBMITS_IN_FLIGHT = 2; private final VulkanDevice device; private final long submitSemaphore; private long currentSubmitIndex = 2L; private long completedSubmitIndex = 0L; private final CheckpointExtension.CheckpointStorage checkpointStorage; private Submission submissionBuilder; private final DestructionQueue destroyQueue = new DestructionQueue<>(2, Destroyable::destroy); private final VulkanCommandPool[] commandPools = new VulkanCommandPool[2]; @Nullable private VkCommandBuffer currentCommandBuffer; @Nullable private VulkanRenderPass currentRenderPass; public VulkanCommandEncoder(final VulkanDevice device) { this.device = device; MemoryStack baseStack = MemoryStack.stackGet(); try (MemoryStack stack = baseStack.push()) { VkSemaphoreTypeCreateInfo semaphoreTypeCreateInfo = VkSemaphoreTypeCreateInfo.calloc(stack).sType$Default(); semaphoreTypeCreateInfo.semaphoreType(1); semaphoreTypeCreateInfo.initialValue(this.currentSubmitIndex - 1L); VkSemaphoreCreateInfo semaphoreCreateInfo = VkSemaphoreCreateInfo.calloc(stack).sType$Default(); semaphoreCreateInfo.pNext(semaphoreTypeCreateInfo); LongBuffer semaphoreHandlePtr = stack.callocLong(1); VulkanUtils.crashIfFailure( device, VK12.vkCreateSemaphore(device.vkDevice(), semaphoreCreateInfo, null, semaphoreHandlePtr), "Failed to create submit VkSemaphore" ); this.submitSemaphore = semaphoreHandlePtr.get(0); } for (int i = 0; i < 2; i++) { this.commandPools[i] = new VulkanCommandPool(device, device.graphicsQueue()); } this.checkpointStorage = device.checkpointExtension().createStorage(device, device.graphicsQueue(), 2); this.submissionBuilder = device.graphicsQueue().beginSubmit(); } @Override public void destroy() { this.submissionBuilder.close(); this.device.graphicsQueue().waitIdle(); this.destroyQueue.close(); for (int i = 0; i < 2; i++) { this.commandPools[i].destroy(); } VK12.vkDestroySemaphore(this.device.vkDevice(), this.submitSemaphore, null); } public void queueForDestroy(final Destroyable destroyable) { this.destroyQueue.add(destroyable); } private VulkanCommandPool currentCommandPool() { return this.commandPools[(int)(this.currentSubmitIndex % 2L)]; } private VulkanGpuBuffer createStagingBuffer(final ByteBuffer data) { int size = data.remaining(); VulkanGpuBuffer stagingBuffer = new VulkanGpuBuffer(this.device, () -> "Staging buffer", 22, size, false); try (MappedView mappedMemory = stagingBuffer.map(0L, data.remaining(), false, true)) { MemoryUtil.memCopy(data, mappedMemory.data()); } return stagingBuffer; } public VkCommandBuffer allocateAndBeginTransientCommandBuffer() { VkCommandBuffer var4; try (MemoryStack stack = MemoryStack.stackPush()) { VkCommandBuffer commandBuffer = this.currentCommandPool().allocateBuffer(); VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.calloc(stack).sType$Default(); beginInfo.flags(1); VulkanUtils.crashIfFailure(this.device, VK12.vkBeginCommandBuffer(commandBuffer, beginInfo), "Failed to begin VkCommandBuffer"); var4 = commandBuffer; } return var4; } private VkCommandBuffer commandBuffer() { if (this.currentCommandBuffer != null) { return this.currentCommandBuffer; } else if (this.currentRenderPass != null) { throw new IllegalStateException("Cannot start command buffer while inside RenderPass"); } else { this.currentCommandBuffer = this.allocateAndBeginTransientCommandBuffer(); this.submissionBuilder.executeCommands(this.currentCommandBuffer); return this.currentCommandBuffer; } } VkCommandBuffer textureInitCommandBuffer() { return this.commandBuffer(); } private void endCommandBuffer() { if (this.currentCommandBuffer != null) { if (this.currentRenderPass != null) { throw new IllegalStateException("Cannot end command buffer while inside RenderPass"); } else { VulkanUtils.crashIfFailure(this.device, VK12.vkEndCommandBuffer(this.currentCommandBuffer), "Failed to end VkCommandBuffer"); this.currentCommandBuffer = null; } } } public void waitSemaphore(final long vkSemaphore, final long value, final long stageMask) { if (this.currentRenderPass != null) { throw new IllegalStateException("Cannot add semaphore operation while inside RenderPass"); } else { this.endCommandBuffer(); this.submissionBuilder.waitSemaphore(vkSemaphore, value, stageMask); } } public void execute(final VkCommandBuffer commandBuffer) { if (this.currentRenderPass != null) { throw new IllegalStateException("Cannot execute command buffer while inside RenderPass"); } else { this.endCommandBuffer(); this.submissionBuilder.executeCommands(commandBuffer); } } public void signalSemaphore(final long vkSemaphore, final long value, final long stageMask) { if (this.currentRenderPass != null) { throw new IllegalStateException("Cannot add semaphore operation while inside RenderPass"); } else { this.endCommandBuffer(); this.submissionBuilder.signalSemaphore(vkSemaphore, value, stageMask); } } private void memoryBarrier(final MemoryStack stack) { Buffer memoryBarrier = VkMemoryBarrier2.calloc(1, stack).sType$Default(); memoryBarrier.srcStageMask(65536L); memoryBarrier.srcAccessMask(98304L); memoryBarrier.dstStageMask(65536L); memoryBarrier.dstAccessMask(98304L); VkDependencyInfo depInfo = VkDependencyInfo.calloc(stack).sType$Default(); depInfo.pMemoryBarriers(memoryBarrier); KHRSynchronization2.vkCmdPipelineBarrier2KHR(this.commandBuffer(), depInfo); } @Override public void submit() { this.endCommandBuffer(); this.signalSemaphore(this.submitSemaphore, this.currentSubmitIndex, 65536L); this.submissionBuilder.close(); this.submissionBuilder = this.device.graphicsQueue().beginSubmit(); this.currentSubmitIndex++; if (!this.awaitSubmitCompletion(this.currentSubmitIndex - 2L, 5000L)) { List checkpoints = this.device.checkpointExtension().retrieveCheckpoints(false); throw new IllegalStateException("5s timeout reached when waiting for VK semaphore: " + VulkanUtils.formatCheckpoints(checkpoints)); } else { this.currentCommandPool().reset(); this.destroyQueue.rotate(); this.checkpointStorage.rotate(); } } @Override public RenderPassBackend createRenderPass(final RenderPassDescriptor descriptor) { List>> colorAttachments = descriptor.colorAttachments(); VulkanGpuTextureView[] colorTextures = new VulkanGpuTextureView[colorAttachments.size()]; for (int i = 0; i < colorAttachments.size(); i++) { Attachment> attachment = (Attachment>)colorAttachments.get(i); colorTextures[i] = attachment != null ? (VulkanGpuTextureView)attachment.textureView() : null; } Attachment depthAttachment = descriptor.depthAttachment(); this.device.instance().debug().beginDebugGroup(this.commandBuffer(), descriptor.label()); this.checkpointStorage.recordCheckpoint(this.commandBuffer(), CheckpointExtension.CheckpointType.BEGIN_RENDER_PASS, descriptor.label()); try (MemoryStack stack = MemoryStack.stackPush()) { int width = 0; int height = 0; if (!colorAttachments.isEmpty()) { for (Attachment> colorAttachment : colorAttachments) { if (colorAttachment != null) { GpuTextureView colorTexture = colorAttachment.textureView(); width = colorTexture.getWidth(0); height = colorTexture.getHeight(0); } } } else if (depthAttachment != null) { width = depthAttachment.textureView().getWidth(0); height = depthAttachment.textureView().getHeight(0); } VkRect2D vkRenderArea = VkRect2D.calloc(stack); if (descriptor.renderArea != null) { vkRenderArea.extent().set(descriptor.renderArea.width(), descriptor.renderArea.height()); vkRenderArea.offset().set(descriptor.renderArea.x(), descriptor.renderArea.y()); } else { vkRenderArea.extent().set(width, height); vkRenderArea.offset().set(0, 0); } org.lwjgl.vulkan.VkRenderingAttachmentInfo.Buffer colorAttachmentInfo = VkRenderingAttachmentInfo.calloc(colorAttachments.size(), stack); for (int i = 0; i < colorAttachments.size(); i++) { colorAttachmentInfo.position(i).sType$Default(); VulkanGpuTextureView colorTexture = colorTextures[i]; if (colorTexture != null) { colorAttachmentInfo.imageView(colorTexture.vkImageView()); colorAttachmentInfo.imageLayout(1); colorAttachmentInfo.storeOp(0); Attachment> attachment = (Attachment>)colorAttachments.get(i); Optional clearValue = attachment.clearValue(); if (clearValue.isPresent()) { Vector4fc color = (Vector4fc)clearValue.get(); VkClearColorValue vkClearColor = VulkanUtils.putArgb(VkClearColorValue.calloc(stack), color); colorAttachmentInfo.loadOp(1); colorAttachmentInfo.clearValue(VkClearValue.calloc(stack).color(vkClearColor)); } else { colorAttachmentInfo.loadOp(0); } } else { colorAttachmentInfo.imageView(0L); colorAttachmentInfo.imageLayout(0); colorAttachmentInfo.storeOp(1); colorAttachmentInfo.loadOp(2); } } colorAttachmentInfo.position(0); VkRenderingInfo renderingInfo = VkRenderingInfo.calloc(stack).sType$Default(); renderingInfo.renderArea(vkRenderArea); renderingInfo.layerCount(1); renderingInfo.viewMask(0); renderingInfo.pColorAttachments(colorAttachmentInfo); if (depthAttachment != null) { VkRenderingAttachmentInfo depthAttachmentInfo = VkRenderingAttachmentInfo.calloc(stack).sType$Default(); VulkanGpuTextureView vulkanDepthAttachment = (VulkanGpuTextureView)depthAttachment.textureView(); depthAttachmentInfo.imageView(vulkanDepthAttachment.vkImageView()); depthAttachmentInfo.imageLayout(1); depthAttachmentInfo.storeOp(0); OptionalDouble clearValue = depthAttachment.clearValue(); if (clearValue.isPresent()) { double color = clearValue.getAsDouble(); VkClearDepthStencilValue vkClearColor = VkClearDepthStencilValue.calloc(stack).depth((float)color); depthAttachmentInfo.loadOp(1); depthAttachmentInfo.clearValue(VkClearValue.calloc(stack).depthStencil(vkClearColor)); } else { depthAttachmentInfo.loadOp(0); } renderingInfo.pDepthAttachment(depthAttachmentInfo); } KHRDynamicRendering.vkCmdBeginRenderingKHR(this.commandBuffer(), renderingInfo); this.currentRenderPass = new VulkanRenderPass( this.device, this, this.commandBuffer(), this.checkpointStorage, descriptor.renderArea, width, height, depthAttachment != null, descriptor.label() ); } return this.currentRenderPass; } @Override public void submitRenderPass() { if (this.currentRenderPass == null) { throw new IllegalStateException("Cannot submit a renderpass if one hasn't been started!"); } else { KHRDynamicRendering.vkCmdEndRenderingKHR(this.commandBuffer()); this.device.instance().debug().endDebugGroup(this.commandBuffer()); this.checkpointStorage.recordCheckpoint(this.commandBuffer(), CheckpointExtension.CheckpointType.END_RENDER_PASS, this.currentRenderPass.getLabel()); this.currentRenderPass = null; try (MemoryStack stack = MemoryStack.stackPush()) { this.memoryBarrier(stack); } } } private void clearColorTextureUnsynced(final MemoryStack stack, final GpuTexture colorTexture, final Vector4fc clearColor) { VkClearColorValue vkClearColor = VulkanUtils.putArgb(VkClearColorValue.calloc(stack), clearColor); VkImageSubresourceRange subresourceRange = VkImageSubresourceRange.calloc(stack); subresourceRange.baseMipLevel(0); subresourceRange.levelCount(colorTexture.getMipLevels()); subresourceRange.baseArrayLayer(0); subresourceRange.layerCount(1); subresourceRange.aspectMask(1); VK12.vkCmdClearColorImage(this.commandBuffer(), ((VulkanGpuTexture)colorTexture).vkImage(), 1, vkClearColor, subresourceRange); } public void clearDepthTextureUnsynced(final MemoryStack stack, final GpuTexture depthTexture, final double clearDepth) { VkClearDepthStencilValue vkClearDepth = VkClearDepthStencilValue.calloc(stack).depth((float)clearDepth); VkImageSubresourceRange subresourceRange = VkImageSubresourceRange.calloc(stack); subresourceRange.baseMipLevel(0); subresourceRange.levelCount(depthTexture.getMipLevels()); subresourceRange.baseArrayLayer(0); subresourceRange.layerCount(1); subresourceRange.aspectMask(2); VK12.vkCmdClearDepthStencilImage(this.commandBuffer(), ((VulkanGpuTexture)depthTexture).vkImage(), 1, vkClearDepth, subresourceRange); } @Override public void clearColorTexture(final GpuTexture colorTexture, final Vector4fc clearColor) { try (MemoryStack stack = MemoryStack.stackPush()) { this.clearColorTextureUnsynced(stack, colorTexture, clearColor); this.memoryBarrier(stack); } } @Override public void clearColorAndDepthTextures(final GpuTexture colorTexture, final Vector4fc clearColor, final GpuTexture depthTexture, final double clearDepth) { try (MemoryStack stack = MemoryStack.stackPush()) { this.clearColorTextureUnsynced(stack, colorTexture, clearColor); this.clearDepthTextureUnsynced(stack, depthTexture, clearDepth); this.memoryBarrier(stack); } } @Override public void clearColorAndDepthTextures( final GpuTexture colorTexture, final Vector4fc clearColor, final GpuTexture depthTexture, final double clearDepth, final int regionX, final int regionY, final int regionWidth, final int regionHeight ) { try ( GpuTextureView colorTextureView = this.device.createTextureView(colorTexture); GpuTextureView depthTextureView = this.device.createTextureView(depthTexture); MemoryStack stack = MemoryStack.stackPush(); ) { this.createRenderPass( RenderPassDescriptor.create(() -> "ClearColorDepthTextures") .withColorAttachment(colorTextureView) .withDepthAttachment(depthTextureView) .withRenderArea(new RenderPass.RenderArea(0, 0, colorTexture.getWidth(0), colorTexture.getHeight(0))) ); assert this.currentRenderPass != null; org.lwjgl.vulkan.VkClearRect.Buffer rects = VkClearRect.calloc(1, stack); rects.baseArrayLayer(0); rects.layerCount(1); rects.rect().offset().set(regionX, regionY); rects.rect().extent().set(regionWidth, regionHeight); org.lwjgl.vulkan.VkClearAttachment.Buffer attachments = VkClearAttachment.calloc(2, stack); VkClearValue colorClearValue = VkClearValue.calloc(stack); VulkanUtils.putArgb(colorClearValue.color(), clearColor); attachments.aspectMask(1); attachments.clearValue(colorClearValue); VkClearValue depthClearValue = VkClearValue.calloc(stack); VkClearDepthStencilValue clearValue = depthClearValue.depthStencil(); clearValue.depth((float)clearDepth); attachments.position(1); attachments.aspectMask(2); attachments.clearValue(depthClearValue); attachments.position(0); VK12.vkCmdClearAttachments(this.commandBuffer(), attachments, rects); this.submitRenderPass(); } } @Override public void clearDepthTexture(final GpuTexture depthTexture, final double clearDepth) { try (MemoryStack stack = MemoryStack.stackPush()) { this.clearDepthTextureUnsynced(stack, depthTexture, clearDepth); this.memoryBarrier(stack); } } @Override public void writeToBuffer(final GpuBufferSlice destination, final ByteBuffer data) { VulkanGpuBuffer destBuffer = (VulkanGpuBuffer)destination.buffer(); try ( VulkanGpuBuffer stagingBuffer = this.createStagingBuffer(data); MemoryStack stack = MemoryStack.stackPush(); ) { org.lwjgl.vulkan.VkBufferCopy.Buffer regions = VkBufferCopy.calloc(1, stack).srcOffset(0L).dstOffset(destination.offset()).size(data.remaining()); VK12.vkCmdCopyBuffer(this.commandBuffer(), stagingBuffer.vkBuffer(), destBuffer.vkBuffer(), regions); this.memoryBarrier(stack); } } @Override public void copyToBuffer(final GpuBufferSlice source, final GpuBufferSlice target) { try (MemoryStack stack = MemoryStack.stackPush()) { org.lwjgl.vulkan.VkBufferCopy.Buffer copyInfo = VkBufferCopy.calloc(1, stack); copyInfo.srcOffset(source.offset()); copyInfo.dstOffset(target.offset()); copyInfo.size(source.length()); VK12.vkCmdCopyBuffer(this.commandBuffer(), ((VulkanGpuBuffer)source.buffer()).vkBuffer(), ((VulkanGpuBuffer)target.buffer()).vkBuffer(), copyInfo); this.memoryBarrier(stack); } } @Override public void writeToTexture( final GpuTexture destination, final NativeImage source, final int mipLevel, final int depthOrLayer, final int destX, final int destY, final int width, final int height, final int sourceX, final int sourceY ) { int stagingBufferSize = source.getWidth() * source.getHeight() * destination.getFormat().pixelSize(); int texelSize = destination.getFormat().pixelSize(); int skipTexels = sourceX + sourceY * source.getWidth(); long skipBytes = (long)skipTexels * texelSize; try (VulkanGpuBuffer stagingBuffer = this.createStagingBuffer(MemoryUtil.memByteBuffer(source.getPointer(), stagingBufferSize))) { this.writeToTexture( (VulkanGpuTexture)destination, stagingBuffer, skipBytes, mipLevel, depthOrLayer, destX, destY, width, height, source.getWidth(), source.getHeight() ); } } @Override public void writeToTexture( final GpuTexture destination, final ByteBuffer source, final Format format, final int mipLevel, final int depthOrLayer, final int destX, final int destY, final int width, final int height ) { try (VulkanGpuBuffer stagingBuffer = this.createStagingBuffer(source)) { this.writeToTexture((VulkanGpuTexture)destination, stagingBuffer, 0L, mipLevel, depthOrLayer, destX, destY, width, height, width, height); } } private void writeToTexture( final VulkanGpuTexture destination, final VulkanGpuBuffer stagingBuffer, final long bufferOffset, final int mipLevel, final int depthOrLayer, final int destX, final int destY, final int width, final int height, final int srcWidth, final int srcHeight ) { try (MemoryStack stack = MemoryStack.stackPush()) { org.lwjgl.vulkan.VkBufferImageCopy.Buffer region = VkBufferImageCopy.calloc(1, stack); region.bufferOffset(bufferOffset); region.bufferRowLength(srcWidth); region.bufferImageHeight(srcHeight); VkImageSubresourceLayers imageSubresource = region.imageSubresource(); imageSubresource.aspectMask(1); imageSubresource.mipLevel(mipLevel); imageSubresource.baseArrayLayer(depthOrLayer); imageSubresource.layerCount(1); region.imageOffset().set(destX, destY, 0); region.imageExtent().set(width, height, 1); VK12.vkCmdCopyBufferToImage(this.commandBuffer(), stagingBuffer.vkBuffer(), destination.vkImage(), 1, region); this.memoryBarrier(stack); } } @Override public void copyTextureToBuffer(final GpuTexture source, final GpuBuffer destination, final long offset, final Runnable callback, final int mipLevel) { this.copyTextureToBuffer(source, destination, offset, callback, mipLevel, 0, 0, source.getWidth(mipLevel), source.getHeight(mipLevel)); } @Override public void copyTextureToBuffer( final GpuTexture source, final GpuBuffer destination, final long offset, final Runnable callback, final int mipLevel, final int x, final int y, final int width, final int height ) { try (MemoryStack stack = MemoryStack.stackPush()) { org.lwjgl.vulkan.VkBufferImageCopy.Buffer copy = VkBufferImageCopy.calloc(1, stack); copy.bufferOffset(offset); VkImageSubresourceLayers subresource = copy.imageSubresource(); subresource.aspectMask(VulkanConst.formatAspectMask(source.getFormat())); subresource.mipLevel(mipLevel); subresource.baseArrayLayer(0); subresource.layerCount(1); copy.imageOffset().set(x, y, 0); copy.imageExtent().set(width, height, 1); copy.bufferRowLength(width); copy.bufferImageHeight(height); VK12.vkCmdCopyImageToBuffer(this.commandBuffer(), ((VulkanGpuTexture)source).vkImage(), 1, ((VulkanGpuBuffer)destination).vkBuffer(), copy); this.memoryBarrier(stack); } this.queueForDestroy(callback::run); } @Override public void copyTextureToTexture( final GpuTexture source, final GpuTexture destination, final int mipLevel, final int destX, final int destY, final int sourceX, final int sourceY, final int width, final int height ) { VulkanGpuTexture vulkanSrc = (VulkanGpuTexture)source; VulkanGpuTexture vulkanDst = (VulkanGpuTexture)destination; try (MemoryStack stack = MemoryStack.stackPush()) { VkImageSubresourceLayers subresourceLayers = VkImageSubresourceLayers.calloc(stack); subresourceLayers.mipLevel(mipLevel); subresourceLayers.baseArrayLayer(0); subresourceLayers.layerCount(1); subresourceLayers.aspectMask(VulkanConst.formatAspectMask(source.getFormat())); org.lwjgl.vulkan.VkImageCopy.Buffer regions = VkImageCopy.calloc(1, stack); regions.srcOffset().set(sourceX, sourceY, 0); regions.dstOffset().set(destX, destY, 0); regions.extent().set(width, height, 1); regions.srcSubresource(subresourceLayers); regions.dstSubresource(subresourceLayers); VK12.vkCmdCopyImage(this.commandBuffer(), vulkanSrc.vkImage(), 1, vulkanDst.vkImage(), 1, regions); this.memoryBarrier(stack); } } private boolean awaitSubmitCompletion(final long submitIndex, final long timeoutMs) { if (this.completedSubmitIndex >= submitIndex) { return true; } else if (submitIndex == this.currentSubmitIndex) { throw new IllegalStateException("Cannot wait on a fence for the current submit"); } else { boolean var9; try (MemoryStack stack = MemoryStack.stackPush()) { VkSemaphoreWaitInfo waitInfo = VkSemaphoreWaitInfo.calloc(stack).sType$Default(); waitInfo.pSemaphores(stack.longs(this.submitSemaphore)); waitInfo.pValues(stack.longs(submitIndex)); waitInfo.semaphoreCount(1); int result = VK12.vkWaitSemaphores(this.device.vkDevice(), waitInfo, timeoutMs * 1000000L); VulkanUtils.crashIfFailure(this.device, result, "Failed to wait for semaphore"); boolean completed = result == 0; if (completed) { this.completedSubmitIndex = submitIndex; } var9 = completed; } return var9; } } @Override public GpuFence createFence() { return new GpuFence() { private final long submitIndex; private boolean completed; { Objects.requireNonNull(VulkanCommandEncoder.this); this.submitIndex = VulkanCommandEncoder.this.currentSubmitIndex; this.completed = false; } @Override public boolean awaitCompletion(final long timeoutMs) { if (!this.completed) { this.completed = VulkanCommandEncoder.this.awaitSubmitCompletion(this.submitIndex, timeoutMs); } return this.completed; } @Override public void close() { this.completed = true; } }; } @Override public void writeTimestamp(final GpuQueryPool pool, final int index) { long queryPool = ((VulkanQueryPool)pool).vkQueryPool(); VK12.vkResetQueryPool(this.device.vkDevice(), queryPool, index, 1); KHRSynchronization2.vkCmdWriteTimestamp2KHR(this.commandBuffer(), 65536L, queryPool, index); } public long getTimestampNow() { long var5; try ( MemoryStack stack = MemoryStack.stackPush(); VulkanQueryPool queryPool = (VulkanQueryPool)this.device.createTimestampQueryPool(1); ) { VkCommandBuffer commandBuffer = this.allocateAndBeginTransientCommandBuffer(); KHRSynchronization2.vkCmdWriteTimestamp2KHR(commandBuffer, 0L, queryPool.vkQueryPool(), 0); VulkanUtils.crashIfFailure(this.device, VK12.vkEndCommandBuffer(commandBuffer), "Failed to end VkCommandBuffer"); try (Submission submit = this.device.graphicsQueue().beginSubmit()) { submit.executeCommands(commandBuffer); } LongBuffer timestampPtr = stack.callocLong(1); VulkanUtils.crashIfFailure( this.device, VK12.vkGetQueryPoolResults(this.device.vkDevice(), queryPool.vkQueryPool(), 0, 1, timestampPtr, 0L, 3), "Cannot fetch current timestamp" ); var5 = timestampPtr.get(0); } return var5; } }