vertexInputInfo.pVertexBindingDescriptions=&bindingDescription;//Array of Vertex defining details for moving vertex data around.
vertexInputInfo.vertexAttributeDescriptionCount=static_cast<uint32_t>(attributeDescription.size());//Need a uint32_t vertion of the size of attributeDescriptions.
vertexInputInfo.pVertexAttributeDescriptions=attributeDescription.data();//Array of Vertex defining details for loading vertex attributes.
//VkPipelineInputAssemblyStateCreateInfo describes inputted geometry from vertices, and primitive restart status. topology member values:
...
...
@@ -1276,10 +1347,14 @@ class HelloTriangleApplication {
// Buffer to record to, graphics/compute pipeline, then the pipeline.
vkCmdBindVertexBuffers(commandBuffers[i],0,1,vertexBuffers,offsets);//Bind the vertex buffers to bindings.
// /\ Fields: command buffer, offset, # of bindings to specify vert buffers for, array of vertex buffers to bind, byte offsets to read vertex data from.
//Buffer to record to, vertexCount, instanceCount (1 if not doing that), firstVertex (vertex buffer offset), firstInstance (instance offset).
vkCmdDraw(commandBuffers[i],3,1,0,0);
vkCmdDraw(commandBuffers[i],static_cast<uint32_t>(vertices.size()),1,0,0);//vertexCount is now dynamic to vertices.
//End the render pass.
vkCmdEndRenderPass(commandBuffers[i]);
...
...
@@ -1304,6 +1379,88 @@ class HelloTriangleApplication {
//We did bitwise ANDs to check for binary intersections between memtypes/memtype index, and the properties of the memory type and the properties we want.
// We may have more than one desirable property - so, we need to check the bitwise AND for properties, that it equals the desired properties bit field, so we find
// a memory type that has everything we need and want.
returni;
}
}
throwstd::runtime_error("Failed to find suitable memory type!");
}
voidcreateVertexBuffer(){
// Buffers in Vulkan are regions of memory storing arbitrary data to be read by the GPU. Here, they store vertex data.
// Buffers DO NOT automatically allocate memory for themselves!
throwstd::runtime_error("Failed to create vertex buffer!");
}
//Now. The buffer has been created, but it doesn't have any memory actually assigned to it yet. So, we allocate!
// \/ Struct Fields: size (bytes of required memory), alignment (offset in bytes to where the buffer begins), memoryTypeBits (bit field of memory types suitable for the buffer.
VkMemoryRequirementsmemRequirements;
vkGetBufferMemoryRequirements(device,vertexBuffer,&memRequirements);//We need to query the buffer's memory requirements.
// This allows us to access a region of specified memory defined by an offset and a size (0 and bufferInfo.sie).
// One can also specify VK_WHOLE_SIZE to map all of the memory.
// Second to last param can be used for flags, but there aren't any yet.
memcpy(data,vertices.data(),(size_t)bufferInfo.size);//memcpy copies into the "data" pointer, from "vertices.data()" pointer, using bufferInfo.size bytes).
vkUnmapMemory(device,vertexBufferMemory);//Unmap once CPU --> GPU memory copy is complete.
//Unfortunately the driver might not immediately copy the data, for example b/c of caching - buffer writes might not be visible in mapped memory yet. Two ways to prevent:
// Call a host-coherent memory heap. Ensures the mapped memory always matches the contents of the allocated memory. Worse performance, but doesn't matter here.
// Call vkFlushMappedMemoryRanges after writing to mapped memory, then call vkInvalidateMappedMemoryRanges after reading from mapped memory. More work!
}
voidinitVulkan(){
createInstance();//The Vulkan instance is the link between application and Vulkan.
setupDebugCallback();//Setup the debug callback that interfaces with the validation layer.
...
...
@@ -1316,6 +1473,7 @@ class HelloTriangleApplication {
createGraphicsPipeline();//The graphics pipeline is completely immutable - we have to build it from scratch, for performance.
createFramebuffers();//Make the framebuffers for all the images in the swap chain - and use the one that corresponds to the retrieved image at draw time.
createCommandPool();//Commands, like draw/memory transfer, are executed by command buffer objects. All the hard setup can be done in multiple threads, then!
createVertexBuffer();//Vertex buffers store vertex data to be read by the GPU.
createCommandBuffers();// We need one command buffer for each image in the swap chain, because they bind to framebuffers.
createSemaphore();//Create the sephamores we need to synchronize things.
}
...
...
@@ -1413,6 +1571,9 @@ class HelloTriangleApplication {
voidcleanup(){
cleanupSwapChain();//Does swapchain related cleanup.
vkDestroyBuffer(device,vertexBuffer,nullptr);//Kill the vertex buffer. It does not depend on the swap chain.
vkFreeMemory(device,vertexBufferMemory,nullptr);//We need to free all allocated memory manually. This is the memory holding the vertex buffer.