20bool VulkanRenderer::CreateSSAOImages() {
22 m_ssaoExtent.width = scExtent.width;
23 m_ssaoExtent.height = scExtent.height;
25 auto createR8 = [&](VkImage& image, VkDeviceMemory& mem, VkImageView& view) ->
bool {
26 VkImageCreateInfo info{};
27 info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
28 info.imageType = VK_IMAGE_TYPE_2D;
29 info.extent.width = m_ssaoExtent.width;
30 info.extent.height = m_ssaoExtent.height;
31 info.extent.depth = 1;
34 info.format = m_ssaoFormat;
35 info.tiling = VK_IMAGE_TILING_OPTIMAL;
36 info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
39 info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
40 | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
41 info.samples = VK_SAMPLE_COUNT_1_BIT;
42 info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
43 if (vkCreateImage(device, &info,
nullptr, &image) != VK_SUCCESS)
return false;
45 VkMemoryRequirements req;
46 vkGetImageMemoryRequirements(device, image, &req);
47 VkMemoryAllocateInfo alloc{};
48 alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
49 alloc.allocationSize = req.size;
50 alloc.memoryTypeIndex = FindMemoryType(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
51 if (vkAllocateMemory(device, &alloc,
nullptr, &mem) != VK_SUCCESS)
return false;
52 vkBindImageMemory(device, image, mem, 0);
54 VkImageViewCreateInfo vinfo{};
55 vinfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
57 vinfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
58 vinfo.format = m_ssaoFormat;
59 vinfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
60 return vkCreateImageView(device, &vinfo,
nullptr, &view) == VK_SUCCESS;
63 if (!createR8(m_ssaoRawImage, m_ssaoRawMemory, m_ssaoRawView))
return false;
64 if (!createR8(m_ssaoBlurImage, m_ssaoBlurMemory, m_ssaoBlurView))
return false;
68 VkSamplerCreateInfo ls{};
69 ls.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
70 ls.magFilter = VK_FILTER_LINEAR;
71 ls.minFilter = VK_FILTER_LINEAR;
72 ls.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
73 ls.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
74 ls.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
75 ls.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
78 if (vkCreateSampler(device, &ls,
nullptr, &m_ssaoSampler) != VK_SUCCESS)
return false;
82 VkSamplerCreateInfo ps{};
83 ps.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
84 ps.magFilter = VK_FILTER_NEAREST;
85 ps.minFilter = VK_FILTER_NEAREST;
86 ps.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
87 ps.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
88 ps.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
89 ps.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
92 if (vkCreateSampler(device, &ps,
nullptr, &m_ssaoPointSampler) != VK_SUCCESS)
return false;
98bool VulkanRenderer::CreateSSAORenderPass() {
101 VkAttachmentDescription colorAtt{};
102 colorAtt.format = m_ssaoFormat;
103 colorAtt.samples = VK_SAMPLE_COUNT_1_BIT;
104 colorAtt.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
105 colorAtt.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
106 colorAtt.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
107 colorAtt.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
108 colorAtt.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
109 colorAtt.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
111 VkAttachmentReference colorRef{};
112 colorRef.attachment = 0;
113 colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
115 VkSubpassDescription subpass{};
116 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
117 subpass.colorAttachmentCount = 1;
118 subpass.pColorAttachments = &colorRef;
120 std::array<VkSubpassDependency, 2> deps{};
121 deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
122 deps[0].dstSubpass = 0;
123 deps[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
124 deps[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
125 deps[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
126 deps[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
127 deps[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
129 deps[1].srcSubpass = 0;
130 deps[1].dstSubpass = VK_SUBPASS_EXTERNAL;
131 deps[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
132 deps[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
133 deps[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
134 deps[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
135 deps[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
137 VkRenderPassCreateInfo rp{};
138 rp.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
139 rp.attachmentCount = 1;
140 rp.pAttachments = &colorAtt;
142 rp.pSubpasses = &subpass;
143 rp.dependencyCount =
static_cast<uint32_t
>(deps.size());
144 rp.pDependencies = deps.data();
146 return vkCreateRenderPass(device, &rp,
nullptr, &m_ssaoRenderPass) == VK_SUCCESS;
150bool VulkanRenderer::CreateSSAOFramebuffers() {
151 auto makeFB = [&](VkImageView v, VkFramebuffer& out) ->
bool {
152 VkFramebufferCreateInfo fb{};
153 fb.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
154 fb.renderPass = m_ssaoRenderPass;
155 fb.attachmentCount = 1;
156 fb.pAttachments = &v;
157 fb.width = m_ssaoExtent.width;
158 fb.height = m_ssaoExtent.height;
160 return vkCreateFramebuffer(device, &fb,
nullptr, &out) == VK_SUCCESS;
162 if (!makeFB(m_ssaoRawView, m_ssaoRawFramebuffer))
return false;
163 if (!makeFB(m_ssaoBlurView, m_ssaoBlurFramebuffer))
return false;
168bool VulkanRenderer::CreateSSAODescriptorResources() {
172 std::array<VkDescriptorSetLayoutBinding, 3> binds{};
173 for (uint32_t i = 0; i < 3; ++i) {
174 binds[i].binding = i;
175 binds[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
176 binds[i].descriptorCount = 1;
177 binds[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
179 VkDescriptorSetLayoutCreateInfo info{};
180 info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
181 info.bindingCount =
static_cast<uint32_t
>(binds.size());
182 info.pBindings = binds.data();
183 if (vkCreateDescriptorSetLayout(device, &info,
nullptr, &m_ssaoInputDSL) != VK_SUCCESS)
return false;
187 VkDescriptorSetLayoutBinding b{};
189 b.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
190 b.descriptorCount = 1;
191 b.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
192 VkDescriptorSetLayoutCreateInfo info{};
193 info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
194 info.bindingCount = 1;
196 if (vkCreateDescriptorSetLayout(device, &info,
nullptr, &m_ssaoUboDSL) != VK_SUCCESS)
return false;
200 std::array<VkDescriptorSetLayoutBinding, 2> binds{};
201 for (uint32_t i = 0; i < 2; ++i) {
202 binds[i].binding = i;
203 binds[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
204 binds[i].descriptorCount = 1;
205 binds[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
207 VkDescriptorSetLayoutCreateInfo info{};
208 info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
209 info.bindingCount =
static_cast<uint32_t
>(binds.size());
210 info.pBindings = binds.data();
211 if (vkCreateDescriptorSetLayout(device, &info,
nullptr, &m_ssaoBlurDSL) != VK_SUCCESS)
return false;
215 std::array<VkDescriptorPoolSize, 2> sizes{};
216 sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
217 sizes[0].descriptorCount = (4 + 2) * MAX_FRAMES_IN_FLIGHT;
218 sizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
219 sizes[1].descriptorCount = 1 * MAX_FRAMES_IN_FLIGHT;
221 VkDescriptorPoolCreateInfo pool{};
222 pool.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
223 pool.poolSizeCount =
static_cast<uint32_t
>(sizes.size());
224 pool.pPoolSizes = sizes.data();
225 pool.maxSets = 3 * MAX_FRAMES_IN_FLIGHT;
226 if (vkCreateDescriptorPool(device, &pool,
nullptr, &m_ssaoDescriptorPool) != VK_SUCCESS)
return false;
229 auto allocSets = [&](VkDescriptorSetLayout dsl, std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT>& out) ->
bool {
230 std::array<VkDescriptorSetLayout, MAX_FRAMES_IN_FLIGHT> layouts;
232 VkDescriptorSetAllocateInfo a{};
233 a.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
234 a.descriptorPool = m_ssaoDescriptorPool;
235 a.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
236 a.pSetLayouts = layouts.data();
237 return vkAllocateDescriptorSets(device, &a, out.data()) == VK_SUCCESS;
239 if (!allocSets(m_ssaoInputDSL, m_ssaoInputSets))
return false;
240 if (!allocSets(m_ssaoUboDSL, m_ssaoUboSets))
return false;
241 if (!allocSets(m_ssaoBlurDSL, m_ssaoBlurSets))
return false;
244 static constexpr VkDeviceSize uboSize =
sizeof(SSAOParams);
245 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
246 VkBufferCreateInfo bi{};
247 bi.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
249 bi.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
250 bi.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
251 if (vkCreateBuffer(device, &bi,
nullptr, &m_ssaoUboBuffers[i]) != VK_SUCCESS)
return false;
253 VkMemoryRequirements req;
254 vkGetBufferMemoryRequirements(device, m_ssaoUboBuffers[i], &req);
255 VkMemoryAllocateInfo alloc{};
256 alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
257 alloc.allocationSize = req.size;
258 alloc.memoryTypeIndex = FindMemoryType(req.memoryTypeBits,
259 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
260 if (vkAllocateMemory(device, &alloc,
nullptr, &m_ssaoUboMemory[i]) != VK_SUCCESS)
return false;
261 vkBindBufferMemory(device, m_ssaoUboBuffers[i], m_ssaoUboMemory[i], 0);
262 if (vkMapMemory(device, m_ssaoUboMemory[i], 0, uboSize, 0, &m_ssaoUboMapped[i]) != VK_SUCCESS)
return false;
265 VkDescriptorBufferInfo bufInfo{};
266 bufInfo.buffer = m_ssaoUboBuffers[i];
268 bufInfo.range = uboSize;
270 VkWriteDescriptorSet w{};
271 w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
272 w.dstSet = m_ssaoUboSets[i];
274 w.dstArrayElement = 0;
275 w.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
276 w.descriptorCount = 1;
277 w.pBufferInfo = &bufInfo;
278 vkUpdateDescriptorSets(device, 1, &w, 0,
nullptr);
285bool VulkanRenderer::CreateSSAONoiseTexture() {
288 const uint32_t noiseCount = SSAO_NOISE_SIZE * SSAO_NOISE_SIZE;
289 std::array<uint8_t, noiseCount * 4> pixels{};
291 std::mt19937 rng(12345u);
292 std::uniform_real_distribution<float> dist(0.0f, 1.0f);
293 for (uint32_t i = 0; i < noiseCount; ++i) {
294 float x = dist(rng) * 2.0f - 1.0f;
295 float y = dist(rng) * 2.0f - 1.0f;
297 pixels[i * 4 + 0] =
static_cast<uint8_t
>((x * 0.5f + 0.5f) * 255.0f);
298 pixels[i * 4 + 1] =
static_cast<uint8_t
>((y * 0.5f + 0.5f) * 255.0f);
299 pixels[i * 4 + 2] = 128;
300 pixels[i * 4 + 3] = 255;
304 VkImageCreateInfo info{};
305 info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
306 info.imageType = VK_IMAGE_TYPE_2D;
307 info.extent.width = SSAO_NOISE_SIZE;
308 info.extent.height = SSAO_NOISE_SIZE;
309 info.extent.depth = 1;
311 info.arrayLayers = 1;
312 info.format = VK_FORMAT_R8G8B8A8_UNORM;
313 info.tiling = VK_IMAGE_TILING_OPTIMAL;
314 info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
315 info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
316 info.samples = VK_SAMPLE_COUNT_1_BIT;
317 info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
318 if (vkCreateImage(device, &info,
nullptr, &m_ssaoNoiseImage) != VK_SUCCESS)
return false;
320 VkMemoryRequirements req;
321 vkGetImageMemoryRequirements(device, m_ssaoNoiseImage, &req);
322 VkMemoryAllocateInfo alloc{};
323 alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
324 alloc.allocationSize = req.size;
325 alloc.memoryTypeIndex = FindMemoryType(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
326 if (vkAllocateMemory(device, &alloc,
nullptr, &m_ssaoNoiseMemory) != VK_SUCCESS)
return false;
327 vkBindImageMemory(device, m_ssaoNoiseImage, m_ssaoNoiseMemory, 0);
329 VkImageViewCreateInfo vinfo{};
330 vinfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
331 vinfo.image = m_ssaoNoiseImage;
332 vinfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
333 vinfo.format = VK_FORMAT_R8G8B8A8_UNORM;
334 vinfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
335 if (vkCreateImageView(device, &vinfo,
nullptr, &m_ssaoNoiseView) != VK_SUCCESS)
return false;
338 VkBuffer staging = VK_NULL_HANDLE;
339 VkDeviceMemory stagingMemory = VK_NULL_HANDLE;
340 const VkDeviceSize uploadSize = pixels.size();
342 VkBufferCreateInfo bi{};
343 bi.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
344 bi.size = uploadSize;
345 bi.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
346 bi.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
347 if (vkCreateBuffer(device, &bi,
nullptr, &staging) != VK_SUCCESS)
return false;
349 VkMemoryRequirements sreq;
350 vkGetBufferMemoryRequirements(device, staging, &sreq);
351 VkMemoryAllocateInfo salloc{};
352 salloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
353 salloc.allocationSize = sreq.size;
354 salloc.memoryTypeIndex = FindMemoryType(sreq.memoryTypeBits,
355 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
356 if (vkAllocateMemory(device, &salloc,
nullptr, &stagingMemory) != VK_SUCCESS) {
357 vkDestroyBuffer(device, staging,
nullptr);
360 vkBindBufferMemory(device, staging, stagingMemory, 0);
362 void* mapped =
nullptr;
363 vkMapMemory(device, stagingMemory, 0, uploadSize, 0, &mapped);
364 memcpy(mapped, pixels.data(), pixels.size());
365 vkUnmapMemory(device, stagingMemory);
368 VkCommandBufferAllocateInfo cbAlloc{};
369 cbAlloc.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
370 cbAlloc.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
371 cbAlloc.commandPool = commands;
372 cbAlloc.commandBufferCount = 1;
374 vkAllocateCommandBuffers(device, &cbAlloc, &cmd);
376 VkCommandBufferBeginInfo begin{};
377 begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
378 begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
379 vkBeginCommandBuffer(cmd, &begin);
381 VkImageMemoryBarrier b0{};
382 b0.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
383 b0.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
384 b0.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
385 b0.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
386 b0.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
387 b0.image = m_ssaoNoiseImage;
388 b0.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
389 b0.srcAccessMask = 0;
390 b0.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
391 vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
392 0, 0,
nullptr, 0,
nullptr, 1, &b0);
394 VkBufferImageCopy region{};
395 region.bufferOffset = 0;
396 region.bufferRowLength = 0;
397 region.bufferImageHeight = 0;
398 region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
399 region.imageOffset = {0, 0, 0};
400 region.imageExtent = {SSAO_NOISE_SIZE, SSAO_NOISE_SIZE, 1};
401 vkCmdCopyBufferToImage(cmd, staging, m_ssaoNoiseImage,
402 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
404 VkImageMemoryBarrier b1 = b0;
405 b1.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
406 b1.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
407 b1.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
408 b1.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
409 vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
410 0, 0,
nullptr, 0,
nullptr, 1, &b1);
412 vkEndCommandBuffer(cmd);
414 VkSubmitInfo submit{};
415 submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
416 submit.commandBufferCount = 1;
417 submit.pCommandBuffers = &cmd;
418 vkQueueSubmit(graphicsQueue, 1, &submit, VK_NULL_HANDLE);
419 vkQueueWaitIdle(graphicsQueue);
421 vkFreeCommandBuffers(device, commands, 1, &cmd);
422 vkDestroyBuffer(device, staging,
nullptr);
423 vkFreeMemory(device, stagingMemory,
nullptr);
426 VkSamplerCreateInfo ns{};
427 ns.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
428 ns.magFilter = VK_FILTER_NEAREST;
429 ns.minFilter = VK_FILTER_NEAREST;
430 ns.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
431 ns.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
432 ns.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
433 ns.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
436 if (vkCreateSampler(device, &ns,
nullptr, &m_ssaoNoiseSampler) != VK_SUCCESS)
return false;
442bool VulkanRenderer::CreateSSAOPipelines() {
444 m_ssaoShader =
new VulkanShader(device);
445 if (!m_ssaoShader->compile(
"assets/shaders/ssao.vert.spv",
446 "assets/shaders/ssao.frag.spv")) {
447 SLEAK_ERROR(
"SSAO: failed to compile ssao shaders");
451 std::array<VkDescriptorSetLayout, 2> ssaoLayouts = { m_ssaoInputDSL, m_ssaoUboDSL };
452 VkPipelineLayoutCreateInfo pli{};
453 pli.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
454 pli.setLayoutCount =
static_cast<uint32_t
>(ssaoLayouts.size());
455 pli.pSetLayouts = ssaoLayouts.data();
456 if (vkCreatePipelineLayout(device, &pli,
nullptr, &m_ssaoPipelineLayout) != VK_SUCCESS) {
457 SLEAK_ERROR(
"SSAO: failed to create ssao pipeline layout");
462 VkPipelineShaderStageCreateInfo ssaoStages[] = {
463 m_ssaoShader->GetVertexInfo(),
464 m_ssaoShader->GetFragInfo()
466 VkPipelineVertexInputStateCreateInfo vin{};
467 vin.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
469 VkPipelineInputAssemblyStateCreateInfo ia{};
470 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
471 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
473 std::vector<VkDynamicState> dynStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
474 VkPipelineDynamicStateCreateInfo ds{};
475 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
476 ds.dynamicStateCount =
static_cast<uint32_t
>(dynStates.size());
477 ds.pDynamicStates = dynStates.data();
479 VkPipelineViewportStateCreateInfo vps{};
480 vps.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
481 vps.viewportCount = 1;
482 vps.scissorCount = 1;
484 VkPipelineRasterizationStateCreateInfo rs{};
485 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
486 rs.polygonMode = VK_POLYGON_MODE_FILL;
487 rs.cullMode = VK_CULL_MODE_NONE;
490 VkPipelineMultisampleStateCreateInfo ms{};
491 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
492 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
494 VkPipelineDepthStencilStateCreateInfo dss{};
495 dss.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
497 VkPipelineColorBlendAttachmentState blendAtt{};
498 blendAtt.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
499 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
501 VkPipelineColorBlendStateCreateInfo cb{};
502 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
503 cb.attachmentCount = 1;
504 cb.pAttachments = &blendAtt;
506 VkGraphicsPipelineCreateInfo gpi{};
507 gpi.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
509 gpi.pStages = ssaoStages;
510 gpi.pVertexInputState = &vin;
511 gpi.pInputAssemblyState = &ia;
512 gpi.pViewportState = &vps;
513 gpi.pRasterizationState = &rs;
514 gpi.pMultisampleState = &ms;
515 gpi.pDepthStencilState = &dss;
516 gpi.pColorBlendState = &cb;
517 gpi.pDynamicState = &ds;
518 gpi.layout = m_ssaoPipelineLayout;
519 gpi.renderPass = m_ssaoRenderPass;
522 if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &gpi,
nullptr, &m_ssaoPipeline) != VK_SUCCESS) {
523 SLEAK_ERROR(
"SSAO: failed to create ssao pipeline");
528 m_ssaoBlurShader =
new VulkanShader(device);
529 if (!m_ssaoBlurShader->compile(
"assets/shaders/ssao_blur.vert.spv",
530 "assets/shaders/ssao_blur.frag.spv")) {
531 SLEAK_ERROR(
"SSAO: failed to compile ssao_blur shaders");
535 VkPipelineLayoutCreateInfo pliBlur{};
536 pliBlur.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
537 pliBlur.setLayoutCount = 1;
538 pliBlur.pSetLayouts = &m_ssaoBlurDSL;
539 if (vkCreatePipelineLayout(device, &pliBlur,
nullptr, &m_ssaoBlurPipelineLayout) != VK_SUCCESS) {
540 SLEAK_ERROR(
"SSAO: failed to create ssao blur pipeline layout");
544 VkPipelineShaderStageCreateInfo blurStages[] = {
545 m_ssaoBlurShader->GetVertexInfo(),
546 m_ssaoBlurShader->GetFragInfo()
548 gpi.pStages = blurStages;
549 gpi.layout = m_ssaoBlurPipelineLayout;
550 if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &gpi,
nullptr, &m_ssaoBlurPipeline) != VK_SUCCESS) {
551 SLEAK_ERROR(
"SSAO: failed to create ssao blur pipeline");
559bool VulkanRenderer::CreateSSAOResources() {
560 if (m_ssaoResourcesCreated)
return true;
562 if (!CreateSSAOImages()) {
SLEAK_ERROR(
"SSAO: images failed");
return false; }
563 if (!CreateSSAONoiseTexture()) {
SLEAK_ERROR(
"SSAO: noise failed");
return false; }
564 if (!CreateSSAORenderPass()) {
SLEAK_ERROR(
"SSAO: render pass failed");
return false; }
565 if (!CreateSSAOFramebuffers()) {
SLEAK_ERROR(
"SSAO: framebuffers failed");
return false; }
566 if (!CreateSSAODescriptorResources()) {
SLEAK_ERROR(
"SSAO: descriptors failed");
return false; }
567 if (!CreateSSAOPipelines()) {
SLEAK_ERROR(
"SSAO: pipelines failed");
return false; }
569 m_ssaoResourcesCreated =
true;
570 SLEAK_INFO(
"SSAO resources created ({}x{})", m_ssaoExtent.width, m_ssaoExtent.height);
575void VulkanRenderer::CleanupSSAOResources() {
576 if (!m_ssaoResourcesCreated)
return;
578 if (m_ssaoPipeline) { vkDestroyPipeline(device, m_ssaoPipeline,
nullptr); m_ssaoPipeline = VK_NULL_HANDLE; }
579 if (m_ssaoBlurPipeline) { vkDestroyPipeline(device, m_ssaoBlurPipeline,
nullptr); m_ssaoBlurPipeline = VK_NULL_HANDLE; }
580 if (m_ssaoPipelineLayout) { vkDestroyPipelineLayout(device, m_ssaoPipelineLayout,
nullptr); m_ssaoPipelineLayout = VK_NULL_HANDLE; }
581 if (m_ssaoBlurPipelineLayout) { vkDestroyPipelineLayout(device, m_ssaoBlurPipelineLayout,
nullptr); m_ssaoBlurPipelineLayout = VK_NULL_HANDLE; }
582 delete m_ssaoShader; m_ssaoShader =
nullptr;
583 delete m_ssaoBlurShader; m_ssaoBlurShader =
nullptr;
585 if (m_ssaoRawFramebuffer) { vkDestroyFramebuffer(device, m_ssaoRawFramebuffer,
nullptr); m_ssaoRawFramebuffer = VK_NULL_HANDLE; }
586 if (m_ssaoBlurFramebuffer) { vkDestroyFramebuffer(device, m_ssaoBlurFramebuffer,
nullptr); m_ssaoBlurFramebuffer = VK_NULL_HANDLE; }
587 if (m_ssaoRenderPass) { vkDestroyRenderPass(device, m_ssaoRenderPass,
nullptr); m_ssaoRenderPass = VK_NULL_HANDLE; }
589 if (m_ssaoDescriptorPool) { vkDestroyDescriptorPool(device, m_ssaoDescriptorPool,
nullptr); m_ssaoDescriptorPool = VK_NULL_HANDLE; }
590 if (m_ssaoInputDSL) { vkDestroyDescriptorSetLayout(device, m_ssaoInputDSL,
nullptr); m_ssaoInputDSL = VK_NULL_HANDLE; }
591 if (m_ssaoUboDSL) { vkDestroyDescriptorSetLayout(device, m_ssaoUboDSL,
nullptr); m_ssaoUboDSL = VK_NULL_HANDLE; }
592 if (m_ssaoBlurDSL) { vkDestroyDescriptorSetLayout(device, m_ssaoBlurDSL,
nullptr); m_ssaoBlurDSL = VK_NULL_HANDLE; }
594 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
595 if (m_ssaoUboMapped[i]) { vkUnmapMemory(device, m_ssaoUboMemory[i]); m_ssaoUboMapped[i] =
nullptr; }
596 if (m_ssaoUboBuffers[i]) { vkDestroyBuffer(device, m_ssaoUboBuffers[i],
nullptr); m_ssaoUboBuffers[i] = VK_NULL_HANDLE; }
597 if (m_ssaoUboMemory[i]) { vkFreeMemory(device, m_ssaoUboMemory[i],
nullptr); m_ssaoUboMemory[i] = VK_NULL_HANDLE; }
600 if (m_ssaoRawView) { vkDestroyImageView(device, m_ssaoRawView,
nullptr); m_ssaoRawView = VK_NULL_HANDLE; }
601 if (m_ssaoBlurView) { vkDestroyImageView(device, m_ssaoBlurView,
nullptr); m_ssaoBlurView = VK_NULL_HANDLE; }
602 if (m_ssaoRawImage) { vkDestroyImage(device, m_ssaoRawImage,
nullptr); m_ssaoRawImage = VK_NULL_HANDLE; }
603 if (m_ssaoBlurImage) { vkDestroyImage(device, m_ssaoBlurImage,
nullptr); m_ssaoBlurImage = VK_NULL_HANDLE; }
604 if (m_ssaoRawMemory) { vkFreeMemory(device, m_ssaoRawMemory,
nullptr); m_ssaoRawMemory = VK_NULL_HANDLE; }
605 if (m_ssaoBlurMemory) { vkFreeMemory(device, m_ssaoBlurMemory,
nullptr); m_ssaoBlurMemory = VK_NULL_HANDLE; }
607 if (m_ssaoNoiseView) { vkDestroyImageView(device, m_ssaoNoiseView,
nullptr); m_ssaoNoiseView = VK_NULL_HANDLE; }
608 if (m_ssaoNoiseImage) { vkDestroyImage(device, m_ssaoNoiseImage,
nullptr); m_ssaoNoiseImage = VK_NULL_HANDLE; }
609 if (m_ssaoNoiseMemory) { vkFreeMemory(device, m_ssaoNoiseMemory,
nullptr); m_ssaoNoiseMemory = VK_NULL_HANDLE; }
610 if (m_ssaoNoiseSampler) { vkDestroySampler(device, m_ssaoNoiseSampler,
nullptr); m_ssaoNoiseSampler = VK_NULL_HANDLE; }
612 if (m_ssaoSampler) { vkDestroySampler(device, m_ssaoSampler,
nullptr); m_ssaoSampler = VK_NULL_HANDLE; }
613 if (m_ssaoPointSampler) { vkDestroySampler(device, m_ssaoPointSampler,
nullptr); m_ssaoPointSampler = VK_NULL_HANDLE; }
615 m_ssaoResourcesCreated =
false;
619void VulkanRenderer::UpdateSSAODescriptors() {
620 if (!m_ssaoResourcesCreated)
return;
624 for (uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; ++f) {
626 std::array<VkDescriptorImageInfo, 3> inputInfos{};
628 inputInfos[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
629 inputInfos[0].imageView = m_gbufferViews[1];
630 inputInfos[0].sampler = m_ssaoPointSampler;
632 inputInfos[1].imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
633 inputInfos[1].imageView = depthImageView;
634 inputInfos[1].sampler = m_ssaoPointSampler;
636 inputInfos[2].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
637 inputInfos[2].imageView = m_ssaoNoiseView;
638 inputInfos[2].sampler = m_ssaoNoiseSampler;
640 std::array<VkWriteDescriptorSet, 3> inputWrites{};
641 for (uint32_t i = 0; i < 3; ++i) {
642 inputWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
643 inputWrites[i].dstSet = m_ssaoInputSets[f];
644 inputWrites[i].dstBinding = i;
645 inputWrites[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
646 inputWrites[i].descriptorCount = 1;
647 inputWrites[i].pImageInfo = &inputInfos[i];
649 vkUpdateDescriptorSets(device,
static_cast<uint32_t
>(inputWrites.size()),
650 inputWrites.data(), 0,
nullptr);
653 std::array<VkDescriptorImageInfo, 2> blurInfos{};
654 blurInfos[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
655 blurInfos[0].imageView = m_ssaoRawView;
656 blurInfos[0].sampler = m_ssaoSampler;
658 blurInfos[1].imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
659 blurInfos[1].imageView = depthImageView;
660 blurInfos[1].sampler = m_ssaoPointSampler;
662 std::array<VkWriteDescriptorSet, 2> blurWrites{};
663 for (uint32_t i = 0; i < 2; ++i) {
664 blurWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
665 blurWrites[i].dstSet = m_ssaoBlurSets[f];
666 blurWrites[i].dstBinding = i;
667 blurWrites[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
668 blurWrites[i].descriptorCount = 1;
669 blurWrites[i].pImageInfo = &blurInfos[i];
671 vkUpdateDescriptorSets(device,
static_cast<uint32_t
>(blurWrites.size()),
672 blurWrites.data(), 0,
nullptr);
677void VulkanRenderer::UpdateSSAOUBO() {
678 if (!m_ssaoResourcesCreated || !m_ssaoUboMapped[currentFrame])
return;
681 memcpy(p.View, m_cachedView,
sizeof(p.View));
682 memcpy(p.Projection, m_cachedProjection,
sizeof(p.Projection));
683 memcpy(p.InvViewProj, m_cachedInvViewProj,
sizeof(p.InvViewProj));
688 static bool s_kernelInit =
false;
689 static float s_kernel[SSAO_KERNEL_SIZE][4];
691 std::mt19937 rng(20240520u);
692 std::uniform_real_distribution<float> d(0.0f, 1.0f);
693 for (uint32_t i = 0; i < SSAO_KERNEL_SIZE; ++i) {
694 float x = d(rng) * 2.0f - 1.0f;
695 float y = d(rng) * 2.0f - 1.0f;
697 float len = std::sqrt(x*x + y*y + z*z);
698 if (len < 1e-6f) { x = 0.0f; y = 0.0f; z = 1.0f; len = 1.0f; }
699 x /= len; y /= len; z /= len;
700 float scale = float(i) / float(SSAO_KERNEL_SIZE);
702 scale = 0.1f + 0.9f * scale * scale;
703 s_kernel[i][0] = x * scale;
704 s_kernel[i][1] = y * scale;
705 s_kernel[i][2] = z * scale;
706 s_kernel[i][3] = 0.0f;
710 memcpy(p.Kernel, s_kernel,
sizeof(p.Kernel));
712 p.ScreenW =
static_cast<float>(scExtent.width);
713 p.ScreenH =
static_cast<float>(scExtent.height);
715 p.NoiseScaleX =
static_cast<float>(scExtent.width) /
float(SSAO_NOISE_SIZE);
716 p.NoiseScaleY =
static_cast<float>(scExtent.height) /
float(SSAO_NOISE_SIZE);
724 memcpy(m_ssaoUboMapped[currentFrame], &p,
sizeof(p));
730void VulkanRenderer::InitDisabledEffectFallbacks() {
731 if (m_ssaoBlurImage == VK_NULL_HANDLE ||
732 m_ssrImage == VK_NULL_HANDLE ||
733 m_bloomImage == VK_NULL_HANDLE)
736 VkCommandBufferAllocateInfo ca{};
737 ca.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
738 ca.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
739 ca.commandPool = commands;
740 ca.commandBufferCount = 1;
741 VkCommandBuffer initCmd;
742 if (vkAllocateCommandBuffers(device, &ca, &initCmd) != VK_SUCCESS)
return;
744 VkCommandBufferBeginInfo bi{};
745 bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
746 bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
747 vkBeginCommandBuffer(initCmd, &bi);
749 const VkImageSubresourceRange sr = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
751 struct Prime { VkImage img; VkClearColorValue clr; };
752 VkClearColorValue white{}; white.float32[0] = 1.0f; white.float32[1] = 1.0f;
753 white.float32[2] = 1.0f; white.float32[3] = 1.0f;
754 VkClearColorValue black{};
756 { m_ssaoBlurImage, white },
757 { m_ssrImage, black },
758 { m_bloomImage, black },
761 for (
auto& it : items) {
762 VkImageMemoryBarrier bar{};
763 bar.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
764 bar.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
765 bar.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
766 bar.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
767 bar.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
768 bar.srcAccessMask = 0;
769 bar.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
771 bar.subresourceRange = sr;
772 vkCmdPipelineBarrier(initCmd,
773 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
774 0, 0,
nullptr, 0,
nullptr, 1, &bar);
776 vkCmdClearColorImage(initCmd, it.img,
777 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &it.clr, 1, &sr);
779 bar.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
780 bar.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
781 bar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
782 bar.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
783 vkCmdPipelineBarrier(initCmd,
784 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
785 0, 0,
nullptr, 0,
nullptr, 1, &bar);
788 vkEndCommandBuffer(initCmd);
791 sub.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
792 sub.commandBufferCount = 1;
793 sub.pCommandBuffers = &initCmd;
794 vkQueueSubmit(graphicsQueue, 1, &sub, VK_NULL_HANDLE);
795 vkQueueWaitIdle(graphicsQueue);
796 vkFreeCommandBuffers(device, commands, 1, &initCmd);
798 m_ssaoFallbackPrimed =
true;
799 m_ssrFallbackPrimed =
true;
800 m_bloomFallbackPrimed =
true;
804void VulkanRenderer::RenderSSAOPasses() {
805 if (!m_ssaoResourcesCreated)
return;
814 if (m_ssaoFallbackPrimed)
return;
815 VkImageMemoryBarrier toClear{};
816 toClear.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
817 toClear.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
818 toClear.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
819 toClear.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
820 toClear.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
821 toClear.srcAccessMask = 0;
822 toClear.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
823 toClear.image = m_ssaoBlurImage;
824 toClear.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
825 vkCmdPipelineBarrier(command,
826 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
827 0, 0,
nullptr, 0,
nullptr, 1, &toClear);
829 VkClearColorValue white{};
830 white.float32[0] = 1.0f; white.float32[1] = 1.0f;
831 white.float32[2] = 1.0f; white.float32[3] = 1.0f;
832 VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
833 vkCmdClearColorImage(command, m_ssaoBlurImage,
834 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &white, 1, &range);
836 VkImageMemoryBarrier toRead = toClear;
837 toRead.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
838 toRead.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
839 toRead.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
840 toRead.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
841 vkCmdPipelineBarrier(command,
842 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
843 0, 0,
nullptr, 0,
nullptr, 1, &toRead);
844 m_ssaoFallbackPrimed =
true;
850 m_ssaoFallbackPrimed =
false;
855 VkRenderPassBeginInfo rp{};
856 rp.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
857 rp.renderPass = m_ssaoRenderPass;
858 rp.framebuffer = m_ssaoRawFramebuffer;
859 rp.renderArea.offset = {0, 0};
860 rp.renderArea.extent = m_ssaoExtent;
861 rp.clearValueCount = 0;
863 vkCmdBeginRenderPass(command, &rp, VK_SUBPASS_CONTENTS_INLINE);
864 FillFullscreenViewportScissor(command, m_ssaoExtent);
865 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_ssaoPipeline);
866 VkDescriptorSet ssaoSets[2] = { m_ssaoInputSets[currentFrame], m_ssaoUboSets[currentFrame] };
867 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
868 m_ssaoPipelineLayout, 0, 2, ssaoSets, 0,
nullptr);
869 vkCmdDraw(command, 3, 1, 0, 0);
870 vkCmdEndRenderPass(command);
873 rp.framebuffer = m_ssaoBlurFramebuffer;
874 vkCmdBeginRenderPass(command, &rp, VK_SUBPASS_CONTENTS_INLINE);
875 FillFullscreenViewportScissor(command, m_ssaoExtent);
876 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_ssaoBlurPipeline);
877 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
878 m_ssaoBlurPipelineLayout, 0, 1,
879 &m_ssaoBlurSets[currentFrame], 0,
nullptr);
880 vkCmdDraw(command, 3, 1, 0, 0);
881 vkCmdEndRenderPass(command);
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.