15 struct PushConstants {
21 ExampleWindow(
const std::string path,
const std::string &text,
int width,
int height,
bool fullscreen,
bool enable_vsync) :
mxvk::
VK_Window(text, width, height, fullscreen,
MXVK_VALIDATION, enable_vsync), shader_root((path.empty() ? std::string(HELLO_WORLD_ASSET_DIR) : path) +
"/data") {
setClearColor(0.02f, 0.03f, 0.06f, 1.0f); }
24 if (
device != VK_NULL_HANDLE) {
27 destroyGraphicsPipeline();
33 if (!ensureGraphicsPipeline()) {
37 vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
39 const auto now = std::chrono::steady_clock::now();
40 const float elapsed_seconds = std::chrono::duration<float>(now - start_time).count();
42 const float aspect = (extent.height > 0U) ?
static_cast<float>(extent.width) /
static_cast<float>(extent.height) : 1.0f;
44 const PushConstants push_constants{elapsed_seconds, aspect};
45 vkCmdPushConstants(cmd, pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0,
sizeof(PushConstants), &push_constants);
47 vkCmdDraw(cmd, 3, 1, 0, 0);
51 std::string shader_root;
52 std::chrono::steady_clock::time_point start_time{std::chrono::steady_clock::now()};
54 void destroyGraphicsPipeline() {
55 if (
device == VK_NULL_HANDLE) {
56 pipeline_layout = VK_NULL_HANDLE;
57 graphics_pipeline = VK_NULL_HANDLE;
61 if (graphics_pipeline != VK_NULL_HANDLE) {
62 vkDestroyPipeline(
device, graphics_pipeline,
nullptr);
63 graphics_pipeline = VK_NULL_HANDLE;
65 if (pipeline_layout != VK_NULL_HANDLE) {
66 vkDestroyPipelineLayout(
device, pipeline_layout,
nullptr);
67 pipeline_layout = VK_NULL_HANDLE;
71 bool ensureGraphicsPipeline() {
72 if (graphics_pipeline != VK_NULL_HANDLE && pipeline_layout != VK_NULL_HANDLE) {
76 createGraphicsPipeline();
77 return graphics_pipeline != VK_NULL_HANDLE && pipeline_layout != VK_NULL_HANDLE;
80 void createGraphicsPipeline() {
85 const std::string vert_path = shader_root +
"/triangle.vert.spv";
86 const std::string frag_path = shader_root +
"/triangle.frag.spv";
87 const std::vector<char> vert_bytes =
loadSpv(vert_path);
88 const std::vector<char> frag_bytes =
loadSpv(frag_path);
91 VkShaderModule frag_module = VK_NULL_HANDLE;
95 std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{};
96 shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
97 shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
98 shader_stages[0].module = vert_module;
99 shader_stages[0].pName =
"main";
100 shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
101 shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
102 shader_stages[1].module = frag_module;
103 shader_stages[1].pName =
"main";
105 VkPipelineVertexInputStateCreateInfo vertex_input{};
106 vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
108 VkPipelineInputAssemblyStateCreateInfo input_assembly{};
109 input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
110 input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
111 input_assembly.primitiveRestartEnable = VK_FALSE;
113 VkPipelineViewportStateCreateInfo viewport_state{};
114 viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
115 viewport_state.viewportCount = 1;
116 viewport_state.scissorCount = 1;
118 const VkDynamicState dynamic_states[] = {
119 VK_DYNAMIC_STATE_VIEWPORT,
120 VK_DYNAMIC_STATE_SCISSOR,
122 VkPipelineDynamicStateCreateInfo dynamic_state{};
123 dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
124 dynamic_state.dynamicStateCount = 2;
125 dynamic_state.pDynamicStates = dynamic_states;
127 VkPipelineRasterizationStateCreateInfo rasterizer{};
128 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
129 rasterizer.depthClampEnable = VK_FALSE;
130 rasterizer.rasterizerDiscardEnable = VK_FALSE;
131 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
132 rasterizer.lineWidth = 1.0f;
133 rasterizer.cullMode = VK_CULL_MODE_NONE;
134 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
135 rasterizer.depthBiasEnable = VK_FALSE;
137 VkPipelineMultisampleStateCreateInfo multisampling{};
138 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
139 multisampling.sampleShadingEnable = VK_FALSE;
140 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
142 VkPipelineDepthStencilStateCreateInfo depth_stencil{};
143 depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
144 depth_stencil.depthTestEnable = VK_FALSE;
145 depth_stencil.depthWriteEnable = VK_FALSE;
146 depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
147 depth_stencil.depthBoundsTestEnable = VK_FALSE;
148 depth_stencil.stencilTestEnable = VK_FALSE;
150 VkPipelineColorBlendAttachmentState color_blend_attachment{};
151 color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
152 color_blend_attachment.blendEnable = VK_FALSE;
154 VkPipelineColorBlendStateCreateInfo color_blending{};
155 color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
156 color_blending.logicOpEnable = VK_FALSE;
157 color_blending.attachmentCount = 1;
158 color_blending.pAttachments = &color_blend_attachment;
160 VkPushConstantRange push_constant_range{};
161 push_constant_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
162 push_constant_range.offset = 0;
163 push_constant_range.size =
sizeof(PushConstants);
165 VkPipelineLayoutCreateInfo pipeline_layout_info{};
166 pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
167 pipeline_layout_info.pushConstantRangeCount = 1;
168 pipeline_layout_info.pPushConstantRanges = &push_constant_range;
169 if (vkCreatePipelineLayout(
device, &pipeline_layout_info,
nullptr, &pipeline_layout) != VK_SUCCESS) {
170 throw mxvk::Exception(
"Failed to create pipeline layout");
173 VkPipelineRenderingCreateInfo pipeline_rendering_info{};
174 pipeline_rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
175 pipeline_rendering_info.viewMask = 0;
176 pipeline_rendering_info.colorAttachmentCount = 1;
180 pipeline_rendering_info.depthAttachmentFormat =
depth_format;
183 VkGraphicsPipelineCreateInfo pipeline_info{};
184 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
185 pipeline_info.pNext = &pipeline_rendering_info;
186 pipeline_info.stageCount =
static_cast<uint32_t
>(shader_stages.size());
187 pipeline_info.pStages = shader_stages.data();
188 pipeline_info.pVertexInputState = &vertex_input;
189 pipeline_info.pInputAssemblyState = &input_assembly;
190 pipeline_info.pViewportState = &viewport_state;
191 pipeline_info.pRasterizationState = &rasterizer;
192 pipeline_info.pMultisampleState = &multisampling;
193 pipeline_info.pDepthStencilState = &depth_stencil;
194 pipeline_info.pColorBlendState = &color_blending;
195 pipeline_info.pDynamicState = &dynamic_state;
196 pipeline_info.layout = pipeline_layout;
197 pipeline_info.renderPass = VK_NULL_HANDLE;
198 pipeline_info.subpass = 0;
199 pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
200 pipeline_info.basePipelineIndex = -1;
202 if (vkCreateGraphicsPipelines(
device, VK_NULL_HANDLE, 1, &pipeline_info,
nullptr, &graphics_pipeline) != VK_SUCCESS) {
203 throw mxvk::Exception(
"Failed to create graphics pipeline");
206 if (graphics_pipeline != VK_NULL_HANDLE) {
207 vkDestroyPipeline(
device, graphics_pipeline,
nullptr);
208 graphics_pipeline = VK_NULL_HANDLE;
210 if (pipeline_layout != VK_NULL_HANDLE) {
211 vkDestroyPipelineLayout(
device, pipeline_layout,
nullptr);
212 pipeline_layout = VK_NULL_HANDLE;
214 if (frag_module != VK_NULL_HANDLE) {
215 vkDestroyShaderModule(
device, frag_module,
nullptr);
217 vkDestroyShaderModule(
device, vert_module,
nullptr);
221 vkDestroyShaderModule(
device, frag_module,
nullptr);
222 vkDestroyShaderModule(
device, vert_module,
nullptr);
225 VkPipeline graphics_pipeline = VK_NULL_HANDLE;
226 VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;