-
Notifications
You must be signed in to change notification settings - Fork 2
/
02 Pipelines.kt
381 lines (291 loc) · 13.1 KB
/
02 Pipelines.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
package vulkan.basics
import glm_.L
import glm_.func.rad
import glm_.glm
import glm_.mat4x4.Mat4
import glm_.vec2.Vec2
import glm_.vec3.Vec3
import glm_.vec4.Vec4
import org.lwjgl.system.MemoryUtil.NULL
import vkk.*
import vulkan.VERTEX_BUFFER_BIND_ID
import vulkan.assetPath
import vulkan.base.*
/*
* Vulkan Example - Using different pipelines in one single renderpass
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
fun main(args: Array<String>) {
Pipelines().apply {
setupWindow()
initVulkan()
prepare()
renderLoop()
destroy()
}
}
private class Pipelines : VulkanExampleBase() {
/** Vertex layout for the models */
val vertexLayout = VertexLayout(
VertexComponent.POSITION,
VertexComponent.NORMAL,
VertexComponent.UV,
VertexComponent.COLOR)
object models {
val cube = Model()
}
val uniformBuffer = Buffer()
/** Same uniform buffer layout as shader */
object uboVS : Bufferizable() {
var projection = Mat4()
@Order(1)
var modelView = Mat4()
@Order(2)
val lightPos = Vec4(0f, 2f, 1f, 0f)
}
var pipelineLayout = VkPipelineLayout(NULL)
var descriptorSet = VkDescriptorSet(NULL)
var descriptorSetLayout = VkDescriptorSetLayout(NULL)
object pipelines {
var phong = VkPipeline(NULL)
var wireframe = VkPipeline(NULL)
var toon = VkPipeline(NULL)
}
init {
zoom = -10.5f
rotation(-25f, 15f, 0f)
title = "Pipeline state objects"
//settings.overlay = true
}
override fun destroy() {
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
device.apply {
destroyPipeline(pipelines.phong)
if (deviceFeatures.fillModeNonSolid)
destroyPipeline(pipelines.wireframe)
destroyPipeline(pipelines.toon)
destroyPipelineLayout(pipelineLayout)
destroyDescriptorSetLayout(descriptorSetLayout)
}
models.cube.destroy()
uniformBuffer.destroy()
super.destroy()
}
// Enable physical device features required for this example
override fun getEnabledFeatures() {
// Fill mode non solid is required for wireframe display
if (deviceFeatures.fillModeNonSolid) {
enabledFeatures.fillModeNonSolid = true
// Wide lines must be present for line width > 1.0f
if (deviceFeatures.wideLines)
enabledFeatures.wideLines = true
}
}
override fun buildCommandBuffers() {
val cmdBufInfo = vk.CommandBufferBeginInfo {}
val clearValues = vk.ClearValue(2).also {
it[0].color(defaultClearColor)
it[1].depthStencil(1f, 0)
}
val renderPassBeginInfo = vk.RenderPassBeginInfo {
renderPass = this@Pipelines.renderPass
renderArea.apply {
offset.set(0, 0)
extent.set(size.x, size.y)
}
this.clearValues = clearValues
}
for (i in drawCmdBuffers.indices) {
// Set target frame buffer
renderPassBeginInfo.framebuffer(frameBuffers[i].L)
drawCmdBuffers[i].apply {
begin(cmdBufInfo)
beginRenderPass(renderPassBeginInfo, VkSubpassContents.INLINE)
val viewport = vk.Viewport(size)
setViewport(viewport)
setScissor(size)
bindDescriptorSets(VkPipelineBindPoint.GRAPHICS, pipelineLayout, descriptorSet)
bindVertexBuffers(VERTEX_BUFFER_BIND_ID, models.cube.vertices.buffer)
bindIndexBuffer(models.cube.indices.buffer, VkDeviceSize(0), VkIndexType.UINT32)
// Left : Solid colored
viewport.width = size.x / 3f
setViewport(viewport)
bindPipeline(VkPipelineBindPoint.GRAPHICS, pipelines.phong)
drawIndexed(models.cube.indexCount, 1, 0, 0, 0)
// Center : Toon
viewport.x = size.x / 3f
setViewport(viewport)
bindPipeline(VkPipelineBindPoint.GRAPHICS, pipelines.toon)
// Line width > 1.0f only if wide lines feature is supported
if (deviceFeatures.wideLines)
setLineWidth(2f)
drawIndexed(models.cube.indexCount, 1, 0, 0, 0)
if (deviceFeatures.fillModeNonSolid) {
// Right : Wireframe
viewport.x = size.x / 3f + size.x / 3f
setViewport(viewport)
bindPipeline(VkPipelineBindPoint.GRAPHICS, pipelines.wireframe)
drawIndexed(models.cube.indexCount, 1, 0, 0, 0)
}
drawUI()
endRenderPass()
end()
}
}
}
fun loadAssets() {
models.cube.loadFromFile("$assetPath/models/treasure_smooth.dae", vertexLayout, 1f, vulkanDevice, queue)
}
fun setupDescriptorPool() {
val poolSize = vk.DescriptorPoolSize(VkDescriptorType.UNIFORM_BUFFER, 1)
val descriptorPoolInfo = vk.DescriptorPoolCreateInfo(poolSize, 2)
descriptorPool = device createDescriptorPool descriptorPoolInfo
}
fun setupDescriptorSetLayout() {
val setLayoutBinding = vk.DescriptorSetLayoutBinding(VkDescriptorType.UNIFORM_BUFFER, VkShaderStage.VERTEX_BIT.i, 0)
val descriptorLayout = vk.DescriptorSetLayoutCreateInfo(setLayoutBinding)
descriptorSetLayout = device createDescriptorSetLayout descriptorLayout
val pipelineLayoutCreateInfo = vk.PipelineLayoutCreateInfo(descriptorSetLayout)
pipelineLayout = device createPipelineLayout pipelineLayoutCreateInfo
}
fun setupDescriptorSet() {
val allocInfo = vk.DescriptorSetAllocateInfo(descriptorPool, descriptorSetLayout)
descriptorSet = device allocateDescriptorSets allocInfo
val writeDescriptorSet = vk.WriteDescriptorSet(
descriptorSet,
VkDescriptorType.UNIFORM_BUFFER,
0, // Binding 0 : Vertex shader uniform buffer
uniformBuffer.descriptor)
device updateDescriptorSets writeDescriptorSet
}
fun preparePipelines() {
val inputAssemblyState = vk.PipelineInputAssemblyStateCreateInfo(
VkPrimitiveTopology.TRIANGLE_LIST,
0,
false)
val rasterizationState = vk.PipelineRasterizationStateCreateInfo(
VkPolygonMode.FILL,
VkCullMode.BACK_BIT.i,
VkFrontFace.CLOCKWISE)
val blendAttachmentState = vk.PipelineColorBlendAttachmentState(0xf, false)
val colorBlendState = vk.PipelineColorBlendStateCreateInfo(blendAttachmentState)
val depthStencilState = vk.PipelineDepthStencilStateCreateInfo(true, true, VkCompareOp.LESS_OR_EQUAL)
val viewportState = vk.PipelineViewportStateCreateInfo(1, 1)
val multisampleState = vk.PipelineMultisampleStateCreateInfo(VkSampleCount.`1_BIT`)
val dynamicStateEnables = listOf(VkDynamicState.VIEWPORT, VkDynamicState.SCISSOR, VkDynamicState.LINE_WIDTH)
val dynamicState = vk.PipelineDynamicStateCreateInfo(dynamicStateEnables)
val pipelineCreateInfo = vk.GraphicsPipelineCreateInfo(pipelineLayout, renderPass)
val shaderStages = vk.PipelineShaderStageCreateInfo(2)
pipelineCreateInfo.let {
it.inputAssemblyState = inputAssemblyState
it.rasterizationState = rasterizationState
it.colorBlendState = colorBlendState
it.multisampleState = multisampleState
it.viewportState = viewportState
it.depthStencilState = depthStencilState
it.dynamicState = dynamicState
it.stages = shaderStages
}
// Shared vertex bindings and attributes used by all pipelines
// Binding description
val vertexInputBindings = vk.VertexInputBindingDescription(VERTEX_BUFFER_BIND_ID, vertexLayout.stride, VkVertexInputRate.VERTEX)
// Attribute descriptions
val vertexInputAttributes = vk.VertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, 0, VkFormat.R32G32B32_SFLOAT, 0, // Location 0: Position
VERTEX_BUFFER_BIND_ID, 1, VkFormat.R32G32B32_SFLOAT, Vec3.size, // Location 1: Color
VERTEX_BUFFER_BIND_ID, 2, VkFormat.R32G32_SFLOAT, Vec3.size * 2, // Location 2 : Texture coordinates
VERTEX_BUFFER_BIND_ID, 3, VkFormat.R32G32B32_SFLOAT, Vec3.size * 2 + Vec2.size) // Location 3 : Normal
val vertexInputState = vk.PipelineVertexInputStateCreateInfo {
vertexBindingDescription = vertexInputBindings
vertexAttributeDescriptions = vertexInputAttributes
}
pipelineCreateInfo.vertexInputState = vertexInputState
/* Create the graphics pipeline state objects
We are using this pipeline as the base for the other pipelines (derivatives)
Pipeline derivatives can be used for pipelines that share most of their state
Depending on the implementation this may result in better performance for pipeline switchting and faster creation time */
pipelineCreateInfo.flags = VkPipelineCreate.ALLOW_DERIVATIVES_BIT.i
// Textured pipeline
// Phong shading pipeline
shaderStages[0].loadShader("$assetPath/shaders/pipelines/phong.vert.spv", VkShaderStage.VERTEX_BIT)
shaderStages[1].loadShader("$assetPath/shaders/pipelines/phong.frag.spv", VkShaderStage.FRAGMENT_BIT)
pipelines.phong = device.createPipeline(pipelineCache, pipelineCreateInfo)
// All pipelines created after the base pipeline will be derivatives
pipelineCreateInfo.flags = VkPipelineCreate.DERIVATIVE_BIT.i
// Base pipeline will be our first created pipeline
pipelineCreateInfo.basePipelineHandle = pipelines.phong
// It's only allowed to either use a handle or index for the base pipeline
// As we use the handle, we must set the index to -1 (see section 9.5 of the specification)
pipelineCreateInfo.basePipelineIndex = -1
// Toon shading pipeline
shaderStages[0].loadShader("$assetPath/shaders/pipelines/toon.vert.spv", VkShaderStage.VERTEX_BIT)
shaderStages[1].loadShader("$assetPath/shaders/pipelines/toon.frag.spv", VkShaderStage.FRAGMENT_BIT)
pipelines.toon = device.createGraphicsPipelines(pipelineCache, pipelineCreateInfo)
// Pipeline for wire frame rendering
// Non solid rendering is not a mandatory Vulkan feature
if (deviceFeatures.fillModeNonSolid) {
rasterizationState.polygonMode = VkPolygonMode.LINE
shaderStages[0].loadShader("$assetPath/shaders/pipelines/wireframe.vert.spv", VkShaderStage.VERTEX_BIT)
shaderStages[1].loadShader("$assetPath/shaders/pipelines/wireframe.frag.spv", VkShaderStage.FRAGMENT_BIT)
pipelines.wireframe = device.createGraphicsPipelines(pipelineCache, pipelineCreateInfo)
}
}
// Prepare and initialize uniform buffer containing shader uniforms
fun prepareUniformBuffers() {
// Create the vertex shader uniform buffer block
vulkanDevice.createBuffer(
VkBufferUsage.UNIFORM_BUFFER_BIT.i,
VkMemoryProperty.HOST_VISIBLE_BIT or VkMemoryProperty.HOST_COHERENT_BIT,
uniformBuffer,
VkDeviceSize(uboVS.size.L))
// Map persistent
uniformBuffer.map()
updateUniformBuffers()
}
fun updateUniformBuffers() {
uboVS.projection = glm.perspective(60f.rad, (size.x / 3f) / size.y, 0.1f, 256f)
val viewMatrix = glm.translate(Mat4(1f), Vec3(0f, 0f, zoom))
uboVS.modelView = viewMatrix translate cameraPos
uboVS.modelView
.rotateAssign(rotation.x.rad, 1f, 0f, 0f)
.rotateAssign(rotation.y.rad, 0f, 1f, 0f)
.rotateAssign(rotation.z.rad, 0f, 0f, 1f)
uboVS to uniformBuffer.mapped
}
fun draw() {
super.prepareFrame()
submitInfo.commandBuffer = drawCmdBuffers[currentBuffer]
queue submit submitInfo
super.submitFrame()
}
override fun prepare() {
super.prepare()
loadAssets()
prepareUniformBuffers()
setupDescriptorSetLayout()
preparePipelines()
setupDescriptorPool()
setupDescriptorSet()
buildCommandBuffers()
prepared = true
window.show()
}
override fun render() {
if (!prepared)
return
draw()
}
override fun viewChanged() = updateUniformBuffers()
// virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
// {
// if (!deviceFeatures.fillModeNonSolid) {
// if (overlay->header("Info")) { overlay ->
// text("Non solid fill modes not supported!")
// }
// }
// }
}