Browse Source

Add some details to the notes and fix some cleanup code.

master
Amber 2 years ago
parent
commit
4241089054
  1. 3
      README
  2. 9
      notes.md
  3. 19
      src/main.c

3
README

@ -1 +1,4 @@
Project to learn the vulkan API. Project to learn the vulkan API.
Checkpoints:
`#2deb04f9ed8c9af493e9a922ebc2ea678954d9a3`: first triangle rendering complete

9
notes.md

@ -24,11 +24,20 @@
content will be treated, to draw a simple triangle we can tell vulkan that there will be a single image content will be treated, to draw a simple triangle we can tell vulkan that there will be a single image
that's a color target and that it needs to be cleared to a solid color before drawing. that's a color target and that it needs to be cleared to a solid color before drawing.
Note: a render pass describes the type of images, a `VkFramebuffer` binds specific images to slots. Note: a render pass describes the type of images, a `VkFramebuffer` binds specific images to slots.
Render passes have subpasses, while a render pass describes which images are going to be used the subpasses
describe which ones will be used for what.
- `VkPipeline`, describes the configuration of the graphics card, like viewport size, depth buffer operations, - `VkPipeline`, describes the configuration of the graphics card, like viewport size, depth buffer operations,
the programmable state is specified using `VkShaderModule` objects, which are created from shader bytecode. the programmable state is specified using `VkShaderModule` objects, which are created from shader bytecode.
The driver also needs to know which render targets are going to be used in the pipeline. The driver also needs to know which render targets are going to be used in the pipeline.
All of the settings are configured in advance, and changing them requires creating a new `VkPipeline`. All of the settings are configured in advance, and changing them requires creating a new `VkPipeline`.
Each pipeline is bound to a compatible render pass to it, at a specific subpass of it, the reason for this
is twofold: things such as fragment shaders will end up writing to the attachments, so it makes sense that
a pipeline, which among other things holds shaders, should know which ones and how, secondarily this allows
for optimizations on tiled gpus, which are sometimes able to merge subpasses.
Another important details is that as of later versions of vulkan render passes are not required when enabling
an extension (`VK_KHR_dynamic_rendering`), this simplifies the code at the potential cost of performance on some
hardware.
- Commands are recorded into a `VkCommandBuffer`, the buffers are allocated out of a `VkCommandPool` associated - Commands are recorded into a `VkCommandBuffer`, the buffers are allocated out of a `VkCommandPool` associated
with a queue family, in order to do some simple drawing we need to do the following: with a queue family, in order to do some simple drawing we need to do the following:

19
src/main.c

@ -54,9 +54,6 @@ typedef struct ApplicationState {
VkExtent2D swapchain_extent; VkExtent2D swapchain_extent;
//describes how to access an image and allows access to it //describes how to access an image and allows access to it
VkImageView* swapchain_image_views; VkImageView* swapchain_image_views;
//shaders
VkShaderModule vertex_shader_module;
VkShaderModule fragment_shader_module;
VkRenderPass render_pass; VkRenderPass render_pass;
VkPipelineLayout pipeline_layout; VkPipelineLayout pipeline_layout;
@ -656,24 +653,27 @@ void create_render_pass(ApplicationState* state) {
//color blending : applies operations to mix different fragments that map to the same pixel //color blending : applies operations to mix different fragments that map to the same pixel
void create_graphics_pipeline(ApplicationState* state) { void create_graphics_pipeline(ApplicationState* state) {
//shaders
VkShaderModule vertex_shader_module;
VkShaderModule fragment_shader_module;
size_t vertex_shader_size; size_t vertex_shader_size;
size_t fragment_shader_size; size_t fragment_shader_size;
char* vertex_shader = load_file("./vertex_simple.spv", &vertex_shader_size); char* vertex_shader = load_file("./vertex_simple.spv", &vertex_shader_size);
char* fragment_shader = load_file("./fragment_simple.spv", &fragment_shader_size); char* fragment_shader = load_file("./fragment_simple.spv", &fragment_shader_size);
state->vertex_shader_module = create_shader_module(state, vertex_shader, vertex_shader_size); vertex_shader_module = create_shader_module(state, vertex_shader, vertex_shader_size);
state->fragment_shader_module = create_shader_module(state, fragment_shader, fragment_shader_size); fragment_shader_module = create_shader_module(state, fragment_shader, fragment_shader_size);
VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {0}; VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {0};
vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertex_shader_stage_info.module = state->vertex_shader_module; vertex_shader_stage_info.module = vertex_shader_module;
vertex_shader_stage_info.pName = "main"; vertex_shader_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {0}; VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {0};
fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragment_shader_stage_info.module = state->fragment_shader_module; fragment_shader_stage_info.module = fragment_shader_module;
fragment_shader_stage_info.pName = "main"; fragment_shader_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info}; VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info};
@ -820,6 +820,9 @@ void create_graphics_pipeline(ApplicationState* state) {
exit(1); exit(1);
} }
printf("created graphics pipeline\n"); printf("created graphics pipeline\n");
vkDestroyShaderModule(state->device, vertex_shader_module, NULL);
vkDestroyShaderModule(state->device, fragment_shader_module, NULL);
} }
void create_framebuffers(ApplicationState* state) { void create_framebuffers(ApplicationState* state) {
@ -1034,6 +1037,8 @@ void main_loop(ApplicationState* state) {
draw_frame(state, current_frame); draw_frame(state, current_frame);
glfwPollEvents(); glfwPollEvents();
} }
vkDeviceWaitIdle(state->device);
} }
void terminate(ApplicationState* state) { void terminate(ApplicationState* state) {

Loading…
Cancel
Save