-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
289 additions
and
0 deletions.
There are no files selected for viewing
269 changes: 269 additions & 0 deletions
269
samples/src/main/java/com/github/knokko/boiler/samples/HelloTriangle.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
package com.github.knokko.boiler.samples; | ||
|
||
import com.github.knokko.boiler.builder.BoilerBuilder; | ||
import com.github.knokko.boiler.builder.BoilerSwapchainBuilder; | ||
import com.github.knokko.boiler.builder.instance.ValidationFeatures; | ||
import com.github.knokko.boiler.commands.CommandRecorder; | ||
import com.github.knokko.boiler.pipelines.GraphicsPipelineBuilder; | ||
import com.github.knokko.boiler.pipelines.ShaderInfo; | ||
import com.github.knokko.boiler.swapchain.SwapchainResourceManager; | ||
import com.github.knokko.boiler.sync.WaitSemaphore; | ||
import org.lwjgl.vulkan.*; | ||
|
||
import static com.github.knokko.boiler.exceptions.VulkanFailureException.assertVkSuccess; | ||
import static java.lang.Thread.sleep; | ||
import static org.lwjgl.glfw.GLFW.glfwPollEvents; | ||
import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose; | ||
import static org.lwjgl.system.MemoryStack.stackPush; | ||
import static org.lwjgl.system.MemoryUtil.memFloatBuffer; | ||
import static org.lwjgl.vulkan.KHRSurface.VK_PRESENT_MODE_MAILBOX_KHR; | ||
import static org.lwjgl.vulkan.KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | ||
import static org.lwjgl.vulkan.VK10.*; | ||
|
||
public class HelloTriangle { | ||
|
||
public static void main(String[] args) throws InterruptedException { | ||
var boiler = new BoilerBuilder( | ||
VK_API_VERSION_1_0, "HelloTriangle", VK_MAKE_VERSION(0, 1, 0) | ||
) | ||
.validation(new ValidationFeatures(false, false, false, true, true)) | ||
.window(0L, 1000, 800, new BoilerSwapchainBuilder(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) | ||
.build(); | ||
|
||
int numFramesInFlight = 3; | ||
var commandPool = boiler.commands.createPool( | ||
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, | ||
boiler.queueFamilies().graphics().index(), | ||
"Drawing" | ||
); | ||
var commandBuffers = boiler.commands.createPrimaryBuffers(commandPool, numFramesInFlight, "Drawing"); | ||
long[] commandFences = boiler.sync.createFences(true, numFramesInFlight, "Fence"); | ||
long graphicsPipeline; | ||
long pipelineLayout; | ||
long renderPass; | ||
|
||
try (var stack = stackPush()) { | ||
pipelineLayout = boiler.pipelines.createLayout(stack, null, "DrawingLayout"); | ||
|
||
var attachments = VkAttachmentDescription.calloc(1, stack); | ||
var colorAttachment = attachments.get(0); | ||
colorAttachment.format(boiler.swapchainSettings.surfaceFormat().format()); | ||
colorAttachment.samples(VK_SAMPLE_COUNT_1_BIT); | ||
colorAttachment.loadOp(VK_ATTACHMENT_LOAD_OP_CLEAR); | ||
colorAttachment.storeOp(VK_ATTACHMENT_STORE_OP_STORE); | ||
colorAttachment.stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE); | ||
colorAttachment.stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE); | ||
colorAttachment.initialLayout(VK_IMAGE_LAYOUT_UNDEFINED); | ||
colorAttachment.finalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); | ||
|
||
var colorReference = VkAttachmentReference.calloc(1, stack); | ||
colorReference.attachment(0); | ||
colorReference.layout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); | ||
|
||
var subpass = VkSubpassDescription.calloc(1, stack); | ||
subpass.pipelineBindPoint(VK_PIPELINE_BIND_POINT_GRAPHICS); | ||
subpass.pInputAttachments(null); | ||
subpass.colorAttachmentCount(1); | ||
subpass.pColorAttachments(colorReference); | ||
subpass.pResolveAttachments(null); | ||
subpass.pDepthStencilAttachment(null); | ||
subpass.pPreserveAttachments(null); | ||
|
||
var dependency = VkSubpassDependency.calloc(1, stack); | ||
dependency.srcSubpass(VK_SUBPASS_EXTERNAL); | ||
dependency.dstSubpass(0); | ||
dependency.srcStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); | ||
dependency.srcAccessMask(0); | ||
dependency.dstStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); | ||
dependency.dstAccessMask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); | ||
|
||
var ciRenderPass = VkRenderPassCreateInfo.calloc(stack); | ||
ciRenderPass.sType$Default(); | ||
ciRenderPass.pAttachments(attachments); | ||
ciRenderPass.pSubpasses(subpass); | ||
ciRenderPass.pDependencies(dependency); | ||
|
||
var pRenderPass = stack.callocLong(1); | ||
assertVkSuccess(vkCreateRenderPass( | ||
boiler.vkDevice(), ciRenderPass, null, pRenderPass | ||
), "CreateRenderPass", "TrianglePass"); | ||
renderPass = pRenderPass.get(0); | ||
} | ||
|
||
try (var stack = stackPush()) { | ||
var vertexModule = boiler.pipelines.createShaderModule( | ||
stack, "com/github/knokko/boiler/samples/graphics/triangle.vert.spv", "TriangleVertices" | ||
); | ||
var fragmentModule = boiler.pipelines.createShaderModule( | ||
stack, "com/github/knokko/boiler/samples/graphics/triangle.frag.spv", "TriangleFragments" | ||
); | ||
|
||
var vertexBindings = VkVertexInputBindingDescription.calloc(1, stack); | ||
vertexBindings.binding(0); | ||
vertexBindings.stride(4 * (2 + 3)); | ||
vertexBindings.inputRate(VK_VERTEX_INPUT_RATE_VERTEX); | ||
|
||
var vertexAttributes = VkVertexInputAttributeDescription.calloc(2, stack); | ||
var attributePosition = vertexAttributes.get(0); | ||
attributePosition.location(0); | ||
attributePosition.binding(0); | ||
attributePosition.format(VK_FORMAT_R32G32_SFLOAT); | ||
attributePosition.offset(0); | ||
var attributeColor = vertexAttributes.get(1); | ||
attributeColor.location(1); | ||
attributeColor.binding(0); | ||
attributeColor.format(VK_FORMAT_R32G32B32_SFLOAT); | ||
attributeColor.offset(4 * 2); | ||
|
||
var ciVertexInput = VkPipelineVertexInputStateCreateInfo.calloc(stack); | ||
ciVertexInput.sType$Default(); | ||
ciVertexInput.pVertexBindingDescriptions(vertexBindings); | ||
ciVertexInput.pVertexAttributeDescriptions(vertexAttributes); | ||
|
||
var pipelineBuilder = new GraphicsPipelineBuilder(boiler, stack); | ||
pipelineBuilder.shaderStages( | ||
new ShaderInfo(VK_SHADER_STAGE_VERTEX_BIT, vertexModule, null), | ||
new ShaderInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentModule, null) | ||
); | ||
pipelineBuilder.ciPipeline.pVertexInputState(ciVertexInput); | ||
pipelineBuilder.simpleInputAssembly(); | ||
pipelineBuilder.dynamicViewports(1); | ||
pipelineBuilder.simpleRasterization(VK_CULL_MODE_NONE); | ||
pipelineBuilder.noMultisampling(); | ||
pipelineBuilder.noDepthStencil(); | ||
pipelineBuilder.noColorBlending(1); | ||
pipelineBuilder.dynamicStates(VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR); | ||
|
||
pipelineBuilder.ciPipeline.renderPass(renderPass); | ||
pipelineBuilder.ciPipeline.layout(pipelineLayout); | ||
|
||
graphicsPipeline = pipelineBuilder.build("TrianglePipeline"); | ||
|
||
vkDestroyShaderModule(boiler.vkDevice(), vertexModule, null); | ||
vkDestroyShaderModule(boiler.vkDevice(), fragmentModule, null); | ||
} | ||
|
||
var vertexBuffer = boiler.buffers.createMapped( | ||
3 * 4 * (2 + 3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, "TriangleVertices" | ||
); | ||
var vertices = memFloatBuffer(vertexBuffer.hostAddress(), 3 * (2 + 3)); | ||
// Put color (1, 0, 0) at position (-1, 1) | ||
vertices.put(-1f); | ||
vertices.put(1f); | ||
vertices.put(1f); | ||
vertices.put(0f); | ||
vertices.put(0f); | ||
// Put color (0, 0, 1) at position (1, 1) | ||
vertices.put(1f); | ||
vertices.put(1f); | ||
vertices.put(0f); | ||
vertices.put(0f); | ||
vertices.put(1f); | ||
// Put color (0, 1, 0) at position (0, -1) | ||
vertices.put(0f); | ||
vertices.put(-1f); | ||
vertices.put(0f); | ||
vertices.put(1f); | ||
vertices.put(0f); | ||
|
||
long frameCounter = 0; | ||
var swapchainResources = new SwapchainResourceManager<>(swapchainImage -> { | ||
try (var stack = stackPush()) { | ||
long imageView = boiler.images.createSimpleView( | ||
stack, swapchainImage.vkImage(), boiler.swapchainSettings.surfaceFormat().format(), | ||
VK_IMAGE_ASPECT_COLOR_BIT, "SwapchainView " + swapchainImage.imageIndex() | ||
); | ||
|
||
long framebuffer = boiler.images.createFramebuffer( | ||
stack, renderPass, swapchainImage.width(), swapchainImage.height(), | ||
"TriangleFramebuffer", imageView | ||
); | ||
|
||
return new AssociatedSwapchainResources(framebuffer, imageView); | ||
} | ||
}, resources -> { | ||
vkDestroyFramebuffer(boiler.vkDevice(), resources.framebuffer, null); | ||
vkDestroyImageView(boiler.vkDevice(), resources.imageView, null); | ||
}); | ||
|
||
long referenceTime = System.currentTimeMillis(); | ||
long referenceFrames = 0; | ||
|
||
while (!glfwWindowShouldClose(boiler.glfwWindow())) { | ||
glfwPollEvents(); | ||
|
||
long currentTime = System.currentTimeMillis(); | ||
if (currentTime > 1000 + referenceTime) { | ||
System.out.println("FPS is " + (frameCounter - referenceFrames)); | ||
referenceTime = currentTime; | ||
referenceFrames = frameCounter; | ||
} | ||
|
||
try (var stack = stackPush()) { | ||
var swapchainImage = boiler.swapchains.acquireNextImage(VK_PRESENT_MODE_MAILBOX_KHR); | ||
if (swapchainImage == null) { | ||
//noinspection BusyWait | ||
sleep(100); | ||
continue; | ||
} | ||
|
||
var imageResources = swapchainResources.get(swapchainImage); | ||
WaitSemaphore[] waitSemaphores = { new WaitSemaphore( | ||
swapchainImage.acquireSemaphore(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | ||
)}; | ||
|
||
int frameIndex = (int) (frameCounter % numFramesInFlight); | ||
var commandBuffer = commandBuffers[frameIndex]; | ||
long fence = commandFences[frameIndex]; | ||
boiler.sync.waitAndReset(stack, fence, 100_000_000); | ||
|
||
var recorder = CommandRecorder.begin(commandBuffer, boiler, stack, "DrawCommands"); | ||
|
||
var pColorClear = VkClearValue.calloc(1, stack); | ||
pColorClear.color().float32(stack.floats(0.2f, 0.2f, 0.2f, 1f)); | ||
|
||
var biRenderPass = VkRenderPassBeginInfo.calloc(stack); | ||
biRenderPass.sType$Default(); | ||
biRenderPass.renderPass(renderPass); | ||
biRenderPass.framebuffer(imageResources.framebuffer); | ||
biRenderPass.renderArea().offset().set(0, 0); | ||
biRenderPass.renderArea().extent().set(swapchainImage.width(), swapchainImage.height()); | ||
biRenderPass.clearValueCount(1); | ||
biRenderPass.pClearValues(pColorClear); | ||
|
||
vkCmdBeginRenderPass(commandBuffer, biRenderPass, VK_SUBPASS_CONTENTS_INLINE); | ||
recorder.dynamicViewportAndScissor(swapchainImage.width(), swapchainImage.height()); | ||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); | ||
|
||
vkCmdBindVertexBuffers(commandBuffer, 0, stack.longs(vertexBuffer.vkBuffer()), stack.longs(0)); | ||
|
||
vkCmdDraw(commandBuffer, 3, 1, 0, 0); | ||
vkCmdEndRenderPass(commandBuffer); | ||
assertVkSuccess(vkEndCommandBuffer(commandBuffer), "TriangleDrawing", null); | ||
|
||
boiler.queueFamilies().graphics().queues().get(0).submit( | ||
commandBuffer, "SubmitDraw", waitSemaphores, fence, swapchainImage.presentSemaphore() | ||
); | ||
|
||
boiler.swapchains.presentImage(swapchainImage); | ||
frameCounter += 1; | ||
} | ||
} | ||
|
||
vkDeviceWaitIdle(boiler.vkDevice()); | ||
for (long fence : commandFences) vkDestroyFence(boiler.vkDevice(), fence, null); | ||
|
||
vkDestroyPipelineLayout(boiler.vkDevice(), pipelineLayout, null); | ||
vkDestroyPipeline(boiler.vkDevice(), graphicsPipeline, null); | ||
vkDestroyRenderPass(boiler.vkDevice(), renderPass, null); | ||
vkDestroyCommandPool(boiler.vkDevice(), commandPool, null); | ||
vertexBuffer.destroy(boiler.vmaAllocator()); | ||
boiler.destroyInitialObjects(); | ||
} | ||
|
||
private record AssociatedSwapchainResources( | ||
long framebuffer, | ||
long imageView | ||
) {} | ||
} | ||
|
9 changes: 9 additions & 0 deletions
9
samples/src/main/resources/com/github/knokko/boiler/samples/graphics/triangle.frag
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#version 450 | ||
|
||
layout(location = 0) in vec3 inColor; | ||
|
||
layout(location = 0) out vec4 outColor; | ||
|
||
void main() { | ||
outColor = vec4(inColor, 1.0); | ||
} |
Binary file added
BIN
+568 Bytes
samples/src/main/resources/com/github/knokko/boiler/samples/graphics/triangle.frag.spv
Binary file not shown.
11 changes: 11 additions & 0 deletions
11
samples/src/main/resources/com/github/knokko/boiler/samples/graphics/triangle.vert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#version 450 | ||
|
||
layout(location = 0) in vec2 inPosition; | ||
layout(location = 1) in vec3 inColor; | ||
|
||
layout(location = 0) out vec3 outColor; | ||
|
||
void main() { | ||
gl_Position = vec4(inPosition, 0.0, 1.0); | ||
outColor = inColor; | ||
} |
Binary file added
BIN
+1.05 KB
samples/src/main/resources/com/github/knokko/boiler/samples/graphics/triangle.vert.spv
Binary file not shown.