-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpipeline.py
238 lines (201 loc) · 9.11 KB
/
pipeline.py
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
from config import *
import shaders
class InputBundle:
"""
Classe de entrada para encapsular os parâmetros necessários para criar um pipeline gráfico.
"""
def __init__(self, device,
swapchainImageFormat, swapchainExtent,
vertexFilepath, fragmentFilepath
):
self.device = device
self.swapchainImageFormat = swapchainImageFormat
self.swapchainExtent = swapchainExtent
self.vertexFilepath = vertexFilepath
self.fragmentFilepath = fragmentFilepath
class OuputBundle:
"""
Classe de saída para encapsular os recursos gerados pelo pipeline gráfico: layout, render pass e o próprio pipeline.
"""
def __init__(self, pipelineLayout, renderPass, pipeline):
self.pipelineLayout = pipelineLayout
self.renderPass = renderPass
self.pipeline = pipeline
"""
A função create_render_pass define uma render pass no Vulkan.
Ela descreve os attachments (recursos de buffer, como a cor) e configura os estados de carregamento e armazenamento
para cada subpass, além de como os dados devem ser tratados ao início e final da renderização.
"""
def create_render_pass(device, swapchainImageFormat):
colorAttachment = VkAttachmentDescription(
format = swapchainImageFormat,
samples = VK_SAMPLE_COUNT_1_BIT,
loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp = VK_ATTACHMENT_STORE_OP_STORE,
stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
initialLayout=VK_IMAGE_LAYOUT_UNDEFINED,
finalLayout=VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
)
# Referência para o attachment que será usado no subpass como color attachment
colorAttachmentRef = VkAttachmentReference(
attachment=0,
layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
)
# Descreve o subpass, aqui um único subpass de renderização de cores
subpass = VkSubpassDescription(
pipelineBindPoint=VK_PIPELINE_BIND_POINT_GRAPHICS,
colorAttachmentCount=1,
pColorAttachments=colorAttachmentRef
)
# Criação da render pass
renderPassInfo = VkRenderPassCreateInfo(
sType=VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
attachmentCount=1,
pAttachments=colorAttachment,
subpassCount=1,
pSubpasses=subpass
)
return vkCreateRenderPass(device, renderPassInfo, None)
"""
A função create_pipeline_layout cria o layout do pipeline.
Aqui estamos criando um pipeline simples, sem push constants ou descritores.
"""
def create_pipeline_layout(device):
pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
pushConstantRangeCount = 0,
setLayoutCount = 0
)
return vkCreatePipelineLayout(
device = device, pCreateInfo = pipelineLayoutInfo, pAllocator = None
)
"""
A função create_graphics_pipeline cria um pipeline gráfico completo,
incluindo shaders, estados fixos (como a viewport, rasterizador e blending),
e associa o pipeline ao layout e à render pass.
"""
def create_graphics_pipeline(inputBundle, debug):
# Sem descrição de entrada de vértices, pois não estamos passando dados de vértices (apenas um triângulo por exemplo)
vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
vertexBindingDescriptionCount=0,
vertexAttributeDescriptionCount=0
)
# Configurar a topologia de entrada de vértices, aqui desenhando triângulos!!
inputAssembly = VkPipelineInputAssemblyStateCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
topology=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
primitiveRestartEnable=VK_FALSE #permite o “desmembramento” de topologias de faixas
)
# Carregar e configurar o shader de vértices
if (debug):
print(f"{HEADER}Carregar módulo de sombreamento (shader module): {inputBundle.vertexFilepath}{RESET}")
vertexShaderModule = shaders.create_shader_module(inputBundle.device, inputBundle.vertexFilepath)
vertexShaderStageInfo = VkPipelineShaderStageCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage=VK_SHADER_STAGE_VERTEX_BIT,
module=vertexShaderModule,
pName="main"
)
#Tessellation -> tesselação (nao estamos usando)
#Geometry shader -> shader geometrico (nao estamos usando)
#Pega a saida do shader de tesselacao mas se tiver sem subdivisao pode obter infos extras...
# Definir a área de visualização (viewport) e o recorte (scissor)
viewport = VkViewport(
x=0,
y=0,
width=inputBundle.swapchainExtent.width,
height = inputBundle.swapchainExtent.height,
minDepth=0.0,
maxDepth=1.0
)
#transformação de imagem para framebuffer: recorte
scissor = VkRect2D(
offset=[0,0],
extent=inputBundle.swapchainExtent
)
# Combinação da viewport e do scissor
viewportState = VkPipelineViewportStateCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
viewportCount=1,
pViewports=viewport,
scissorCount=1,
pScissors=scissor
)
# Configurações do rasterizador: define como os fragmentos serão gerados a partir dos vértices
# -> preencher shapes
raterizer = VkPipelineRasterizationStateCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
depthClampEnable=VK_FALSE,
rasterizerDiscardEnable=VK_FALSE,
polygonMode=VK_POLYGON_MODE_FILL,
lineWidth=1.0,
cullMode=VK_CULL_MODE_BACK_BIT,
frontFace=VK_FRONT_FACE_CLOCKWISE,
depthBiasEnable=VK_FALSE #transformação opcional em valores de profundidade
)
# Configurações de multisampling (desativado neste caso)
# melhora a qualidade visual das bordas dos objetos.
# suaviza transicoes entre pixel e elimita o efeito serrilhado (aliasing)
# que pode ocorrer quando linhas e bordas de objetos aparecem de forma
# abrupta e pixelizada.
multisampling = VkPipelineMultisampleStateCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
sampleShadingEnable=VK_FALSE,
rasterizationSamples=VK_SAMPLE_COUNT_1_BIT
)
#O sombreador de fragmentos carrega os fragmentos do rasterizador e os colore apropriadamente
if (debug):
print(f"{HEADER}Carregar módulo de sombreamento (shader module): {inputBundle.fragmentFilepath}{RESET}")
fragmentShaderModule = shaders.create_shader_module(inputBundle.device, inputBundle.fragmentFilepath)
fragmentShaderStageInfo = VkPipelineShaderStageCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
stage=VK_SHADER_STAGE_FRAGMENT_BIT,
module=fragmentShaderModule,
pName="main"
)
#shader vertex, geometry shader (se tiver usado), fragment shader : : em comum!
shaderStages = [vertexShaderStageInfo, fragmentShaderStageInfo]
#Color blend em um anexo de cor especifico (Desativado para este caso)
#combinação de cores, pegue a saída do fragment shader e incorpore-a ao pixel existente, se ele tiver sido definido.
colorBlendAttachment = VkPipelineColorBlendAttachmentState(
colorWriteMask=VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
blendEnable=VK_FALSE #função sem blend
)
#Color blending (desativado para este caso)
colorBlending = VkPipelineColorBlendStateCreateInfo(
sType=VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
logicOpEnable=VK_FALSE, #sem operações lógicas
attachmentCount=1,
pAttachments=colorBlendAttachment,
blendConstants=[0.0, 0.0, 0.0, 0.0]
)
# Criar o layout do pipeline e a render pass
pipelineLayout = create_pipeline_layout(inputBundle.device)
renderPass = create_render_pass(inputBundle.device, inputBundle.swapchainImageFormat)
# Criar o pipeline gráfico
pipelineInfo = VkGraphicsPipelineCreateInfo(
sType=VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
stageCount=2,
pStages=shaderStages,
pVertexInputState=vertexInputInfo,
pInputAssemblyState=inputAssembly,
pViewportState=viewportState,
pRasterizationState=raterizer,
pMultisampleState=multisampling,
pDepthStencilState=None,
pColorBlendState=colorBlending,
layout=pipelineLayout,
renderPass=renderPass,
subpass=0 #índice da subpasta 0, a única subpasta
)
#vkCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines=None)
graphicsPipeline = vkCreateGraphicsPipelines(inputBundle.device, VK_NULL_HANDLE, 1, pipelineInfo, None)[0]
vkDestroyShaderModule(inputBundle.device, vertexShaderModule, None)
vkDestroyShaderModule(inputBundle.device, fragmentShaderModule, None)
return OuputBundle(
pipelineLayout = pipelineLayout,
renderPass = renderPass,
pipeline = graphicsPipeline
)