kiba-engine
pipeline.c
1 #include <kiba/gpu/pipeline.h>
2 #include <kiba/gpu/vulkan/allocator.h>
3 #include <kiba/gpu/vulkan/conv.h>
4 #include <kiba/gpu/vulkan/device.h>
5 #include <kiba/gpu/vulkan/util.h>
6 
7 b8 gpu_backend_pipeline_layout_create(struct gpu_backend_pipeline_layout *layout,
8  struct gpu_backend_device *device,
9  struct gpu_pipeline_layout_descriptor desc) {
10  VkPipelineLayoutCreateInfo info = {
11  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
12  .setLayoutCount = desc.bind_group_layouts ? (u32) array_size(desc.bind_group_layouts) : 0,
13  .pSetLayouts = desc.bind_group_layouts,
14  .pushConstantRangeCount = 0, // TODO
15  .pPushConstantRanges = NULL,
16  };
17  VK_CALL_B8(vkCreatePipelineLayout(device->logical, &info, &vk_alloc.vulkan_callbacks, &layout->raw));
18  vk_device_set_object_name(device->logical, VK_OBJECT_TYPE_PIPELINE_LAYOUT, layout->raw, desc.label);
19  return true;
20 }
21 
22 void gpu_backend_pipeline_layout_destroy(struct gpu_backend_pipeline_layout *layout,
23  struct gpu_backend_device *device) {
24  if (layout->raw != VK_NULL_HANDLE) {
25  vkDestroyPipelineLayout(device->logical, layout->raw, &vk_alloc.vulkan_callbacks);
26  layout->raw = VK_NULL_HANDLE;
27  }
28 }
29 
30 KB_LOCAL b8 gpu_backend_render_pipeline_create(struct gpu_backend_pipeline *pipeline,
31  struct gpu_backend_device *device,
32  struct gpu_render_pipeline_descriptor desc) {
33  VkDynamicState dynamic_states[] = {
34  VK_DYNAMIC_STATE_VIEWPORT,
35  VK_DYNAMIC_STATE_SCISSOR,
36  // TODO may need more, e.g. blend state, stencil reference etc.
37  };
38 
39  // state that can be changed after pipeline creation
40  VkPipelineDynamicStateCreateInfo dynamic_state_info = {
41  .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
42  .dynamicStateCount = sizeof(dynamic_states) / sizeof(dynamic_states[0]),
43  .pDynamicStates = dynamic_states,
44  };
45 
46  // vertex layouts
47  array_of(VkVertexInputBindingDescription) vertex_input_bindings = KB_NULL;
48  array_of(VkVertexInputAttributeDescription) vertex_attributes = KB_NULL;
49  VkPipelineVertexInputStateCreateInfo vertex_input_info = {
50  .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
51  .vertexBindingDescriptionCount = 0,
52  .pVertexBindingDescriptions = vertex_input_bindings,
53  .vertexAttributeDescriptionCount = 0,
54  .pVertexAttributeDescriptions = vertex_attributes,
55  };
56  if (desc.vertex.buffers != KB_NULL) {
57  usize attribute_count = 0;
58  array_for_each(struct gpu_vertex_buffer_layout, layout, desc.vertex.buffers) {
59  attribute_count += array_size(layout->attributes);
60  }
61  vertex_input_bindings =
62  array_create(VkVertexInputBindingDescription, array_size(desc.vertex.buffers), &vk_alloc.kiba_alloc);
63  if (vertex_input_bindings == KB_NULL) {
64  KB_ERROR("could not allocate list of pipeline vertex inputs");
65  return false;
66  }
67  vertex_attributes = array_create(VkVertexInputAttributeDescription, attribute_count, &vk_alloc.kiba_alloc);
68  if (vertex_attributes == KB_NULL) {
69  KB_ERROR("could not allocate list of pipeline vertex input's attribute descriptions");
70  array_destroy(vertex_input_bindings);
71  return false;
72  }
73  u32 binding = 0;
74  array_for_each(struct gpu_vertex_buffer_layout, layout, desc.vertex.buffers) {
75  VkVertexInputBindingDescription input_binding_description = {
76  .binding = binding,
77  .inputRate = vk_convert_step_mode(layout->step_mode),
78  .stride = (u32) layout->stride,
79  };
80  array_push(vertex_input_bindings, input_binding_description);
81  u32 location = 0;
82  array_for_each(struct gpu_vertex_buffer_layout_attribute, attribute, layout->attributes) {
83  VkVertexInputAttributeDescription attribute_description = {
84  .binding = binding,
85  .location = location++,
86  .format = vk_convert_vertex_format(attribute->format),
87  .offset = (u32) attribute->offset,
88  };
89  array_push(vertex_attributes, attribute_description);
90  }
91  ++binding;
92  }
93  vertex_input_info.vertexBindingDescriptionCount = (u32) array_size(vertex_input_bindings);
94  vertex_input_info.pVertexBindingDescriptions = vertex_input_bindings;
95  vertex_input_info.vertexAttributeDescriptionCount = (u32) array_size(vertex_attributes);
96  vertex_input_info.pVertexAttributeDescriptions = vertex_attributes;
97  }
98 
99  // kind of geometry
100  VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {
101  .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
102  .topology = vk_convert_primitive_topology(desc.primitive.topology),
103  .primitiveRestartEnable = VK_FALSE,
104  };
105 
106  VkPipelineViewportStateCreateInfo viewport_state_info = {
107  .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
108  .viewportCount = 1,
109  .scissorCount = 1,
110  };
111 
112  // rasterization
113  VkPipelineRasterizationStateCreateInfo rasterizer_info = {
114  .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
115  .depthClampEnable = VK_FALSE,
116  .rasterizerDiscardEnable = VK_FALSE,
117  .polygonMode = vk_convert_polygon_mode(desc.primitive.polygon_mode),
118  .lineWidth = 1.0f,
119  .cullMode = vk_convert_cull_mode(desc.primitive.cull_mode),
120  .frontFace = vk_convert_front_face(desc.primitive.front_face),
121  .depthBiasEnable = VK_FALSE, // TODO when to toggle on
122 
123  .depthBiasConstantFactor = desc.depth_stencil.depth_bias.constant,
124  .depthBiasClamp = desc.depth_stencil.depth_bias.clamp,
125  .depthBiasSlopeFactor = desc.depth_stencil.depth_bias.slope_scale,
126  };
127 
128  // multisampling TODO
129  VkPipelineMultisampleStateCreateInfo multisampling_info = {
130  .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
131  .sampleShadingEnable = VK_FALSE,
132  .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
133  .minSampleShading = 1.0f,
134  .pSampleMask = NULL,
135  .alphaToCoverageEnable = VK_FALSE,
136  .alphaToOneEnable = VK_FALSE,
137  };
138 
139  // key to find compatible renderpass
140  struct vk_renderpass_key rp_key = {
141  0 // TODO would fill sample_count and multiview here
142  };
143 
144  // TODO descriptor.fragment.active not yet respected
145  // color blending
146  array_of(VkPipelineColorBlendAttachmentState) color_blend_attachments =
147  array_create(VkPipelineColorBlendAttachmentState, array_size(desc.fragment.targets), &vk_alloc.kiba_alloc);
148  if (color_blend_attachments == KB_NULL) {
149  KB_ERROR("failed to allocate list of color blend attachments");
150  return false;
151  }
152  array_for_each(struct gpu_color_target_state, target_state, desc.fragment.targets) {
153  VkPipelineColorBlendAttachmentState color_blend_attachment = {
154  .colorWriteMask = target_state->write_mask,
155  .blendEnable = target_state->blend.active,
156  .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, // TODO not yet implemented in the struct
157  .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
158  .colorBlendOp = VK_BLEND_OP_ADD,
159  .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
160  .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
161  .alphaBlendOp = VK_BLEND_OP_ADD,
162  };
163  array_push(color_blend_attachments, color_blend_attachment);
164  struct vk_attachment_key cak = {
165  .format = vk_convert_texture_format(target_state->format),
166  .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
167  .ops = GPU_ATTACHMENT_OP_ALL,
168  };
169  rp_key.colors[rp_key.color_count++].base = cak;
170  }
171 
172  VkPipelineColorBlendStateCreateInfo color_blend_info = {
173  .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
174  .logicOpEnable = VK_FALSE,
175  .logicOp = VK_LOGIC_OP_COPY,
176  .attachmentCount = (u32) array_size(color_blend_attachments),
177  .pAttachments = color_blend_attachments,
178  .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
179  };
180 
181  // TODO use stencil components? also rest of depth stuff
182  VkPipelineDepthStencilStateCreateInfo depth_info = {
183  .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
184  .depthTestEnable =
185  desc.depth_stencil.depth_compare != GPU_COMPARE_FUNC_ALWAYS || desc.depth_stencil.depth_write_enabled,
186  .depthWriteEnable = desc.depth_stencil.depth_write_enabled,
187  .depthCompareOp = vk_convert_compare_function(desc.depth_stencil.depth_compare),
188  .depthBoundsTestEnable = VK_FALSE, // could be used to discard fragments outside of bounds
189  .minDepthBounds = 0.f,
190  .maxDepthBounds = 1.f,
191  .stencilTestEnable = VK_FALSE, // TODO could be used to perform stencil tests, uses `front` and `back` fields
192  };
193  // TODO fill rp_key with depth info in case it's needed
194 
195  // get appropriate render pass
196  VkRenderPass renderpass;
197  if (!vk_device_create_renderpass(device, rp_key, &renderpass)) {
198  KB_ERROR("could not create renderpass for pipeline");
199  return false;
200  }
201 
202  // shaders
203  VkPipelineShaderStageCreateInfo shader_stages[2] = {
204  {
205  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
206  .stage = VK_SHADER_STAGE_VERTEX_BIT,
207  .module = desc.vertex.shader->bs.raw,
208  .pName = desc.vertex.entry_point,
209  },
210  {
211  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
212  .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
213  .module = desc.fragment.shader->bs.raw,
214  .pName = desc.fragment.entry_point,
215  },
216  };
217 
218  VkGraphicsPipelineCreateInfo pipeline_info = {
219  .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
220  .stageCount = sizeof(shader_stages) / sizeof(shader_stages[0]),
221  .pStages = shader_stages,
222  .pVertexInputState = &vertex_input_info,
223  .pInputAssemblyState = &input_assembly_info,
224  .pViewportState = &viewport_state_info,
225  .pRasterizationState = &rasterizer_info,
226  .pMultisampleState = &multisampling_info,
227  .pDepthStencilState = &depth_info,
228  .pColorBlendState = &color_blend_info,
229  .pDynamicState = &dynamic_state_info,
230  .layout = desc.layout->bl.raw,
231  .renderPass = renderpass,
232  .subpass = 0,
233  .basePipelineHandle = VK_NULL_HANDLE,
234  .basePipelineIndex = -1,
235  };
236  VK_CALL_B8(vkCreateGraphicsPipelines(device->logical,
237  VK_NULL_HANDLE,
238  1,
239  &pipeline_info,
240  &vk_alloc.vulkan_callbacks,
241  &pipeline->raw));
242  vk_device_set_object_name(device->logical, VK_OBJECT_TYPE_PIPELINE, pipeline->raw, desc.label);
243  array_destroy(&color_blend_attachments);
244  array_destroy(&vertex_attributes);
245  array_destroy(&vertex_input_bindings);
246 
247  return true;
248 }
249 
250 void gpu_backend_render_pipeline_destroy(struct gpu_backend_pipeline *pipeline, struct gpu_backend_device *device) {
251  if (pipeline->raw != VK_NULL_HANDLE) {
252  vkDestroyPipeline(device->logical, pipeline->raw, &vk_alloc.vulkan_callbacks);
253  pipeline->raw = VK_NULL_HANDLE;
254  }
255 }
#define KB_NULL
Value of an invalid ptr (nullptr).
Definition: defines.h:18
#define KB_ERROR(...)
Log entry with error log level.
Definition: log.h:142