Commit for 2020.07.18.7z

This commit is contained in:
mrq 2020-07-18 00:00:00 -05:00
parent e3e28a8910
commit e1736f573a
46 changed files with 562 additions and 582 deletions

View File

@ -1,12 +1,10 @@
#version 450
layout (set = 0, binding = 1) uniform texture2D tex;
layout (set = 0, binding = 2) uniform sampler samp;
layout (input_attachment_index = 0, binding = 1) uniform subpassInput samplerAlbedo;
layout (location = 0) in vec2 inUv;
layout (location = 0) out vec4 outFragColor;
void main() {
outFragColor = texture(sampler2D(tex, samp), inUv);
// outFragColor = vec4(inUv, 1.0f, 0.0f);
outFragColor = subpassLoad(samplerAlbedo);
}

View File

@ -3,10 +3,6 @@
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout (binding = 0) uniform UBO {
vec2 screenSize;
} ubo;
layout (location = 0) out vec2 outUv;
out gl_PerVertex {

View File

@ -0,0 +1,10 @@
#version 450
layout (input_attachment_index = 0, binding = 1) uniform subpassInput samplerAlbedo;
layout (location = 0) in vec2 inUv;
layout (location = 0) out vec4 outFragColor;
void main() {
outFragColor = subpassLoad(samplerAlbedo);
}

View File

@ -0,0 +1,17 @@
#version 450
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 0) out vec2 outUv;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
gl_Position = vec4(inPos.xy, 0.0, 1.0);
}

View File

@ -8,11 +8,14 @@ namespace ext {
uint32_t width, height;
// RAII
virtual const std::string& getName() const;
virtual size_t subpasses() const;
virtual void initialize( Device& device );
virtual void createCommandBuffers();
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void destroy();
virtual VkRenderPass& getRenderPass();
};
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/rendertarget.h>
#include <uf/ext/vulkan/graphics/framebuffer.h>
namespace ext {
namespace vulkan {
struct UF_API DeferredCommand : public ext::vulkan::Command {
ext::vulkan::RenderTarget framebuffer;
ext::vulkan::FramebufferGraphic blitter;
// RAII
virtual const std::string& getName() const;
virtual size_t subpasses() const;
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void initialize( Device& device );
virtual void destroy();
virtual VkRenderPass& getRenderPass();
};
}
}

View File

@ -15,10 +15,13 @@ namespace ext {
// RAII
virtual const std::string& getName() const;
virtual size_t subpasses() const;
virtual void createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes );
virtual void render();
virtual void initialize( Device& device );
virtual void destroy();
virtual VkRenderPass& getRenderPass();
};
}
}

View File

@ -22,6 +22,7 @@ namespace ext {
} uniforms;
uint32_t indices = 0;
VkSampler sampler;
ext::vulkan::RenderTarget* framebuffer;
virtual void createCommandBuffer( VkCommandBuffer );

View File

@ -283,7 +283,7 @@ namespace ext {
return descriptorSetAllocateInfo;
}
inline VkDescriptorImageInfo descriptorImageInfo(VkSampler sampler, VkImageView imageView, VkImageLayout imageLayout)
inline VkDescriptorImageInfo descriptorImageInfo(VkImageView imageView, VkImageLayout imageLayout, VkSampler sampler = VK_NULL_HANDLE)
{
VkDescriptorImageInfo descriptorImageInfo {};
descriptorImageInfo.sampler = sampler;

View File

@ -6,22 +6,34 @@ namespace ext {
namespace vulkan {
struct UF_API RenderTarget {
typedef struct {
VkImage image;
VkFormat format;
VkImageLayout layout;
VkImageUsageFlags usage;
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} Attachment;
std::vector<Attachment> attachments;
typedef struct {
VkPipelineStageFlags stage;
VkAccessFlags access;
std::vector<VkAttachmentReference> colors;
std::vector<VkAttachmentReference> inputs;
VkAttachmentReference depth;
} Subpass;
std::vector<Subpass> passes;
Device* device = nullptr;
VkSampler sampler;
VkDescriptorImageInfo descriptorImageInfo;
VkRenderPass renderPass;
VkFramebuffer framebuffer;
std::vector<VkFramebuffer> framebuffers;
bool commandBufferSet;
// RAII
void initialize( Device& device );
void destroy();
void addPass( VkPipelineStageFlags, VkAccessFlags, const std::vector<size_t>&, const std::vector<size_t>&, size_t );
size_t attach( VkFormat format, VkImageUsageFlags usage, Attachment* attachment = NULL );
};
}
}

View File

@ -8,6 +8,12 @@
const std::string& ext::vulkan::Command::getName() const {
return "Base";
}
size_t ext::vulkan::Command::subpasses() const {
return 1;
}
VkRenderPass& ext::vulkan::Command::getRenderPass() {
return swapchain.renderPass;
}
void ext::vulkan::Command::createCommandBuffers() {
std::vector<void*> graphics;

View File

@ -0,0 +1,217 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/commands/deferred.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/utils/mesh/mesh.h>
namespace {
// 0 left 1 right
uint8_t DOMINANT_EYE = 1;
}
const std::string& ext::vulkan::DeferredCommand::getName() const {
return "Defered";
}
size_t ext::vulkan::DeferredCommand::subpasses() const {
return framebuffer.passes.size();
}
VkRenderPass& ext::vulkan::DeferredCommand::getRenderPass() {
return framebuffer.renderPass;
}
void ext::vulkan::DeferredCommand::initialize( Device& device ) {
{
framebuffer.device = &device;
// attach targets
struct {
size_t albedo, normals, depth, output;
} attachments;
attachments.albedo = framebuffer.attach( VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // albedo
attachments.normals = framebuffer.attach( VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ); // normals
attachments.depth = framebuffer.attach( swapchain.depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ); // depth
// Attach swapchain's image as output
{
attachments.output = framebuffer.attachments.size();
framebuffer.attachments.push_back({ swapchain.colorFormat, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, });
}
// First pass: fill the G-Buffer
{
framebuffer.addPass(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
{ attachments.albedo, attachments.normals, },
{},
attachments.depth
);
}
// Second pass: write to output
{
framebuffer.addPass(
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT,
{ attachments.output, },
{ attachments.albedo, attachments.normals },
attachments.depth
);
}
}
framebuffer.initialize( device );
blitter.framebuffer = &framebuffer;
blitter.initializeShaders({
{"./data/shaders/display.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
blitter.initialize( device, ext::vulkan::swapchain );
}
void ext::vulkan::DeferredCommand::destroy() {
framebuffer.destroy();
}
void ext::vulkan::DeferredCommand::createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes ) {
// destroy if exists
if ( swapchain.rebuild ) {
if ( swapchain.commandBufferSet ) {
auto* device = swapchain.device;
bool vsync = swapchain.vsync;
swapchain.destroy();
swapchain.initialize( *device, 0, 0, vsync );
}
swapchain.commandBufferSet = true;
// destroy if exist
if ( framebuffer.commandBufferSet ) {
auto* device = framebuffer.device;
framebuffer.initialize( *device );
}
framebuffer.commandBufferSet = true;
// update descriptor set
if ( blitter.initialized ) {
VkDescriptorImageInfo textDescriptorAlbedo = ext::vulkan::initializers::descriptorImageInfo(
framebuffer.attachments[0].view,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
// Binding 0 : Projection/View matrix uniform buffer
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,
&(blitter.buffers.at(0).descriptor)
),
// Binding 1 : Albedo input attachment
ext::vulkan::initializers::writeDescriptorSet(
blitter.descriptorSet,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
1,
&textDescriptorAlbedo
),
};
vkUpdateDescriptorSets( device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr );
}
}
float width = this->width > 0 ? this->width : ext::vulkan::width;
float height = this->height > 0 ? this->height : ext::vulkan::height;
blitter.uniforms.screenSize = { width, height };
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
for (int32_t i = 0; i < swapchain.drawCommandBuffers.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(swapchain.drawCommandBuffers[i], &cmdBufInfo));
// Fill GBuffer
{
std::vector<VkClearValue> clearValues; clearValues.resize(4);
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[2].depthStencil = { 1.0f, 0 };
clearValues[3].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = framebuffer.renderPass;
renderPassBeginInfo.framebuffer = framebuffer.framebuffers[i];
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createImageMemoryBarrier(swapchain.drawCommandBuffers[i]);
}
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass + ";DEFERRED";
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createCommandBuffer(swapchain.drawCommandBuffers[i] );
}
}
vkCmdNextSubpass(swapchain.drawCommandBuffers[i], VK_SUBPASS_CONTENTS_INLINE);
blitter.createCommandBuffer(swapchain.drawCommandBuffers[i]);
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
}
VK_CHECK_RESULT(vkEndCommandBuffer(swapchain.drawCommandBuffers[i]));
}
}
void ext::vulkan::DeferredCommand::render() {
//auto& device = ext::vulkan::device;
//auto& swapchain = ext::vulkan::swapchain;
//auto& currentBuffer = ext::vulkan::currentBuffer;
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(device, 1, &swapchain.waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &swapchain.waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &swapchain.renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &swapchain.drawCommandBuffers[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device.graphicsQueue, 1, &submitInfo, swapchain.waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device.presentQueue, currentBuffer, swapchain.renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device.presentQueue));
}

View File

@ -13,6 +13,13 @@ namespace {
const std::string& ext::vulkan::MultiviewCommand::getName() const {
return "Multiview";
}
size_t ext::vulkan::MultiviewCommand::subpasses() const {
return framebuffers.left.passes.size();
}
VkRenderPass& ext::vulkan::MultiviewCommand::getRenderPass() {
return framebuffers.left.renderPass;
}
void ext::vulkan::MultiviewCommand::initialize( Device& device ) {
framebuffers.left.initialize( device );
framebuffers.right.initialize( device );
@ -135,7 +142,7 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
renderPassBeginInfo.renderPass = framebuffers.left.renderPass;
renderPassBeginInfo.framebuffer = framebuffers.left.framebuffer;
renderPassBeginInfo.framebuffer = framebuffers.left.framebuffers[i];
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
@ -151,7 +158,7 @@ void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
renderPassBeginInfo.renderPass = framebuffers.right.renderPass;
renderPassBeginInfo.framebuffer = framebuffers.right.framebuffer;
renderPassBeginInfo.framebuffer = framebuffers.right.framebuffers[i];
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);

View File

@ -1,276 +0,0 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/commands/multiview.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/utils/window/window.h>
#include <uf/utils/mesh/mesh.h>
namespace {
uf::GuiMesh mesh;
}
const std::string& ext::vulkan::MultiviewCommand::getName() const {
return "Multiview";
}
void ext::vulkan::MultiviewCommand::initialize( Device& device ) {
framebuffers.left.initialize( device );
framebuffers.right.initialize( device );
/*
mesh.vertices = {
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 1.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 1.0f}, },
{ {1.0f, 1.0f}, {1.0f, 0.0f}, }
};
mesh.initialize(true);
*/
}
void ext::vulkan::MultiviewCommand::destroy() {
framebuffers.left.destroy();
framebuffers.right.destroy();
}
void ext::vulkan::MultiviewCommand::createCommandBuffers( const std::vector<void*>& graphics, const std::vector<std::string>& passes ) {
//auto& device = ext::vulkan::device;
//auto& swapchain = ext::vulkan::swapchain;
//auto& currentBuffer = ext::vulkan::currentBuffer;
// destroy if exists
if ( swapchain.commandBufferSet ) {
auto* device = swapchain.device;
bool vsync = swapchain.vsync;
swapchain.destroy();
swapchain.initialize( *device, 0, 0, vsync );
}
swapchain.commandBufferSet = true;
// destroy if exist
if ( framebuffers.left.commandBufferSet ) {
auto* device = framebuffers.left.device;
framebuffers.left.initialize( *device );
}
framebuffers.left.commandBufferSet = true;
// destroy if exist
if ( framebuffers.right.commandBufferSet ) {
auto* device = framebuffers.right.device;
framebuffers.right.initialize( *device );
}
framebuffers.right.commandBufferSet = true;
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
// Set clear values for all framebuffer attachments with loadOp set to clear
// We use two attachments (color and depth) that are cleared at the start of the subpass and as such we need to set clear values for both
VkClearValue clearValues[2];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues;
for (int32_t i = 0; i < swapchain.drawCommandBuffers.size(); ++i) {
// Set target frame buffer
VK_CHECK_RESULT(vkBeginCommandBuffer(swapchain.drawCommandBuffers[i], &cmdBufInfo));
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createImageMemoryBarrier(swapchain.drawCommandBuffers[i]);
}
// Update dynamic viewport state
VkViewport viewport = {};
viewport.height = (float)height;
viewport.width = (float)width;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = framebuffers.left.targets[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.image = framebuffers.left.targets[0].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.left.targets[0].layout = imageMemoryBarrier.newLayout;
// Transition the depth buffer to VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL on first use
if ( framebuffers.left.targets[1].layout == VK_IMAGE_LAYOUT_UNDEFINED ) {
imageMemoryBarrier.image = framebuffers.left.targets[1].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = framebuffers.left.targets[1].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.left.targets[1].layout = imageMemoryBarrier.newLayout;
}
// Start the first sub pass specified in our default render pass setup by the base class
// This will clear the color and depth attachment
renderPassBeginInfo.renderPass = framebuffers.left.renderPass;
renderPassBeginInfo.framebuffer = framebuffers.left.framebuffer;
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass + ";STEREO_LEFT";
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
graphic.createCommandBuffer(swapchain.drawCommandBuffers[i] );
}
}
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
{
// Transition eye image to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for display on the companion window
imageMemoryBarrier.image = framebuffers.left.targets[0].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = framebuffers.left.targets[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.left.targets[0].layout = imageMemoryBarrier.newLayout;
}
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = framebuffers.right.targets[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.image = framebuffers.right.targets[0].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.right.targets[0].layout = imageMemoryBarrier.newLayout;
// Transition the depth buffer to VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL on first use
if ( framebuffers.right.targets[1].layout == VK_IMAGE_LAYOUT_UNDEFINED ) {
imageMemoryBarrier.image = framebuffers.right.targets[1].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = framebuffers.right.targets[1].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.right.targets[1].layout = imageMemoryBarrier.newLayout;
}
renderPassBeginInfo.renderPass = framebuffers.right.renderPass;
renderPassBeginInfo.framebuffer = framebuffers.right.framebuffer;
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
for ( auto pass : passes ) {
ext::vulkan::currentPass = pass + ";STEREO_RIGHT";
for ( auto& pGraphic : graphics ) {
Graphic& graphic = *((Graphic*) pGraphic);
// graphic.createCommandBuffer(swapchain.drawCommandBuffers[i] );
}
}
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
{
// Transition eye image to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for display on the companion window
imageMemoryBarrier.image = framebuffers.right.targets[0].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = framebuffers.right.targets[0].layout;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
framebuffers.right.targets[0].layout = imageMemoryBarrier.newLayout;
}
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.image = swapchain.buffers[i].image;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
vkCmdPipelineBarrier( swapchain.drawCommandBuffers[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
renderPassBeginInfo.renderPass = swapchain.renderPass;
renderPassBeginInfo.framebuffer = swapchain.frameBuffers[i];
vkCmdBeginRenderPass(swapchain.drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(swapchain.drawCommandBuffers[i], 0, 1, &viewport);
vkCmdSetScissor(swapchain.drawCommandBuffers[i], 0, 1, &scissor);
// ::mesh.graphic.createCommandBuffer(swapchain.drawCommandBuffers[i]);
vkCmdEndRenderPass(swapchain.drawCommandBuffers[i]);
// Ending the render pass will add an implicit barrier transitioning the frame buffer color attachment to
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presenting it to the windowing system
VK_CHECK_RESULT(vkEndCommandBuffer(swapchain.drawCommandBuffers[i]));
}
}
void ext::vulkan::MultiviewCommand::render() {
//auto& device = ext::vulkan::device;
//auto& swapchain = ext::vulkan::swapchain;
//auto& currentBuffer = ext::vulkan::currentBuffer;
// Get next image in the swap chain (back/front buffer)
VK_CHECK_RESULT(swapchain.acquireNextImage(&currentBuffer));
// Use a fence to wait until the command buffer has finished execution before using it again
VK_CHECK_RESULT(vkWaitForFences(device, 1, &swapchain.waitFences[currentBuffer], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &swapchain.waitFences[currentBuffer]));
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &swapchain.renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &swapchain.drawCommandBuffers[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device.graphicsQueue, 1, &submitInfo, swapchain.waitFences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device.presentQueue, currentBuffer, swapchain.renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device.presentQueue));
}

View File

@ -229,7 +229,7 @@ VkResult ext::vulkan::Device::createBuffer(
return buffer.bind();
}
void ext::vulkan::Device::initialize() {
void ext::vulkan::Device::initialize() {
const std::vector<const char*> validationLayers = {
"VK_LAYER_LUNARG_standard_validation"
};
@ -288,12 +288,11 @@ void ext::vulkan::Device::initialize() {
break;
}
}
// if ( !found ) dprintf( "Vulkan missing requested extension '%s'.\n", extensions[ nExt ] );
if ( !found ) std::cout << "Vulkan missing requested extension " << extensions[index] << std::endl;
}
}
}
for ( auto ext : supportedExtensions ) std::cout << "Extension: " << ext << std::endl;
// for ( auto ext : supportedExtensions ) std::cout << "Extension: " << ext << std::endl;
// Create instance
{
@ -408,13 +407,8 @@ void ext::vulkan::Device::initialize() {
deviceExtensions.push_back(extensionProperties[index].extensionName);
}
}
// if ( !found ) dprintf( "Vulkan missing requested extension '%s'.\n", extensions[ nExt ] );
if ( !found ) std::cout << "Vulkan missing requested extension " << extensions[index] << std::endl;
}
/*
for ( auto ext : deviceExtensions ) {
std::cout << "Device Extension: " << ext << std::endl;
}
*/
}
}

View File

@ -201,7 +201,7 @@ void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
swapchain.renderPass,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
@ -214,6 +214,7 @@ void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shader.stages.size());
pipelineCreateInfo.pStages = shader.stages.data();
pipelineCreateInfo.subpass = 0;
initializePipeline(pipelineCreateInfo);
}
@ -221,7 +222,7 @@ void ext::vulkan::BaseGraphic::initialize( Device& device, Swapchain& swapchain
initializeDescriptorPool({
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
}, 2);
}, 1);
// Set descriptor set
initializeDescriptorSet({
// Binding 0 : Projection/View matrix uniform buffer

View File

@ -35,6 +35,8 @@ void ext::vulkan::FramebufferGraphic::createCommandBuffer( VkCommandBuffer comma
void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swapchain ) {
this->device = &device;
texture.loadFromFile( "./data/textures/texture.png", ext::vulkan::device, ext::vulkan::device.graphicsQueue );
std::vector<Vertex> vertices = {
{ {-1.0f, 1.0f}, {0.0f, 0.0f}, },
@ -86,16 +88,36 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
),
// Fragment shader
ext::vulkan::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
VK_SHADER_STAGE_FRAGMENT_BIT,
1
),
/*
ext::vulkan::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
2
),
*/
});
// Create sampler
/*
{
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = samplerInfo.addressModeU;
samplerInfo.addressModeW = samplerInfo.addressModeU;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 1.0f;
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, &sampler));
}
*/
// Create uniform buffer
initializeBuffer(
(void*) &uniforms,
@ -188,7 +210,7 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
swapchain.renderPass,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
@ -201,23 +223,21 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shader.stages.size());
pipelineCreateInfo.pStages = shader.stages.data();
pipelineCreateInfo.subpass = 1;
initializePipeline(pipelineCreateInfo);
}
// Set descriptor pool
initializeDescriptorPool({
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1),
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_SAMPLER, 1)
}, 3);
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1),
}, 1);
// Set descriptor set
{
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageLayout = framebuffer->attachments[0].layout;
imageInfo.imageView = framebuffer->attachments[0].view;
VkDescriptorImageInfo samplerInfo = {};
samplerInfo.sampler = framebuffer->sampler;
VkDescriptorImageInfo textDescriptorAlbedo = ext::vulkan::initializers::descriptorImageInfo(
framebuffer->attachments[0].view,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
initializeDescriptorSet({
// Binding 0 : Projection/View matrix uniform buffer
@ -227,6 +247,14 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
0,
&(buffers.at(0).descriptor)
),
// Binding 1 : Albedo input attachment
ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
1,
&textDescriptorAlbedo
),
/*
// Binding 1 : Fragment shader texture
// Fragment shader: layout (binding = 1) uniform texture2D tex;
ext::vulkan::initializers::writeDescriptorSet(
@ -243,6 +271,7 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
2,
&samplerInfo
)
*/
});
}
/*
@ -266,4 +295,5 @@ void ext::vulkan::FramebufferGraphic::initialize( Device& device, Swapchain& swa
}
void ext::vulkan::FramebufferGraphic::destroy() {
ext::vulkan::Graphic::destroy();
// vkDestroySampler( *device, sampler, nullptr );
}

View File

@ -161,7 +161,7 @@ void ext::vulkan::GuiGraphic::initialize( Device& device, Swapchain& swapchain )
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
swapchain.renderPass,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
@ -174,6 +174,7 @@ void ext::vulkan::GuiGraphic::initialize( Device& device, Swapchain& swapchain )
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shader.stages.size());
pipelineCreateInfo.pStages = shader.stages.data();
pipelineCreateInfo.subpass = 0;
initializePipeline(pipelineCreateInfo);
}
@ -181,7 +182,7 @@ void ext::vulkan::GuiGraphic::initialize( Device& device, Swapchain& swapchain )
initializeDescriptorPool({
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
}, 2);
}, 1);
// Set descriptor set
initializeDescriptorSet({
// Binding 0 : Projection/View matrix uniform buffer

View File

@ -167,7 +167,7 @@ void ext::vulkan::MeshGraphic::initialize( Device& device, Swapchain& swapchain
VkGraphicsPipelineCreateInfo pipelineCreateInfo = ext::vulkan::initializers::pipelineCreateInfo(
pipelineLayout,
swapchain.renderPass,
ext::vulkan::command ? ext::vulkan::command->getRenderPass() : swapchain.renderPass,
0
);
pipelineCreateInfo.pVertexInputState = &vertexInputState;
@ -180,6 +180,7 @@ void ext::vulkan::MeshGraphic::initialize( Device& device, Swapchain& swapchain
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shader.stages.size());
pipelineCreateInfo.pStages = shader.stages.data();
pipelineCreateInfo.subpass = 0;
initializePipeline(pipelineCreateInfo);
}
@ -187,7 +188,7 @@ void ext::vulkan::MeshGraphic::initialize( Device& device, Swapchain& swapchain
initializeDescriptorPool({
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
ext::vulkan::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1)
}, 2);
}, 1);
// Set descriptor set
initializeDescriptorSet({
// Binding 0 : Projection/View matrix uniform buffer

View File

@ -7,299 +7,228 @@ namespace {
bool USEVR = false;
}
void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFlags access, const std::vector<size_t>& colors, const std::vector<size_t>& inputs, size_t depth ) {
Subpass pass;
pass.stage = stage;
pass.access = access;
for ( auto& i : colors ) pass.colors.push_back( { i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } );
for ( auto& i : inputs ) pass.inputs.push_back( { i, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } );
pass.depth = { depth, attachments[depth].layout };
passes.push_back(pass);
}
size_t ext::vulkan::RenderTarget::attach( VkFormat format, VkImageUsageFlags usage, Attachment* attachment ) {
if ( width == 0 ) width = ext::vulkan::width;
if ( height == 0 ) height = ext::vulkan::height;
if ( !attachment ) {
attachments.resize(attachments.size()+1);
attachment = &attachments.back();
} else {
vkDestroyImageView(*device, attachment->view, nullptr);
vkDestroyImage(*device, attachment->image, nullptr);
vkFreeMemory(*device, attachment->mem, nullptr);
}
VkImageAspectFlags aspectMask = 0;
// specialization: depth buffer
if ( usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // | VK_IMAGE_ASPECT_STENCIL_BIT;
attachment->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
} else {
aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
attachment->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
attachment->format = format;
attachment->usage = usage;
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = format;
image.extent = { width, height, 1 };
image.mipLevels = 1;
image.arrayLayers = USEVR ? 2 : 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = usage | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(*device, &image, nullptr, &attachment->image));
// Allocate memory for the image (device local) and bind it to our image
VkMemoryAllocateInfo memAlloc = {};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(*device, attachment->image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(*device, &memAlloc, nullptr, &attachment->mem));
VK_CHECK_RESULT(vkBindImageMemory(*device, attachment->image, attachment->mem, 0));
// Create a view for the depth stencil image
// Images aren't directly accessed in Vulkan, but rather through views described by a subresource range
// This allows for multiple views of one image with differing ranges (e.g. for different layers)
VkImageViewCreateInfo imageView = {};
imageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageView.format = format;
imageView.subresourceRange = {};
imageView.subresourceRange.aspectMask = aspectMask;
imageView.subresourceRange.baseMipLevel = 0;
imageView.subresourceRange.levelCount = 1;
imageView.subresourceRange.baseArrayLayer = 0;
imageView.subresourceRange.layerCount = USEVR ? 2 : 1;
imageView.image = attachment->image;
VK_CHECK_RESULT(vkCreateImageView(*device, &imageView, nullptr, &attachment->view));
return attachments.size()-1;
}
void ext::vulkan::RenderTarget::initialize( Device& device ) {
// Bind
{
this->device = &device;
if ( width == 0 ) width = ext::vulkan::width;
if ( height == 0 ) height = ext::vulkan::height;
attachments.resize(2);
}
// color target
auto& color = attachments[0];
// depth target
auto& depthStencil = attachments[1];
{
// Create an optimal image used as the depth stencil attachment
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = ext::vulkan::swapchain.colorFormat;
// Use example's height and width
image.extent = { width, height, 1 };
image.mipLevels = 1;
image.arrayLayers = USEVR ? 2 : 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &color.image));
// Allocate memory for the image (device local) and bind it to our image
VkMemoryAllocateInfo memAlloc = {};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, color.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &color.mem));
VK_CHECK_RESULT(vkBindImageMemory(device, color.image, color.mem, 0));
// Create a view for the depth stencil image
// Images aren't directly accessed in Vulkan, but rather through views described by a subresource range
// This allows for multiple views of one image with differing ranges (e.g. for different layers)
VkImageViewCreateInfo imageView = {};
imageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageView.format = ext::vulkan::swapchain.colorFormat;
imageView.subresourceRange = {};
imageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageView.subresourceRange.baseMipLevel = 0;
imageView.subresourceRange.levelCount = 1;
imageView.subresourceRange.baseArrayLayer = 0;
imageView.subresourceRange.layerCount = USEVR ? 2 : 1;
imageView.image = color.image;
VK_CHECK_RESULT(vkCreateImageView(device, &imageView, nullptr, &color.view));
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = samplerInfo.addressModeU;
samplerInfo.addressModeW = samplerInfo.addressModeU;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 1.0f;
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, &sampler));
// Fill a descriptor for later use in a descriptor set
descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
descriptorImageInfo.imageView = color.view;
descriptorImageInfo.sampler = sampler;
}
// Create depth/stencil buffer
{
// Create an optimal image used as the depth stencil attachment
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = ext::vulkan::swapchain.depthFormat;
// Use example's height and width
image.extent = { width, height, 1 };
image.mipLevels = 1;
image.arrayLayers = 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthStencil.image));
// Allocate memory for the image (device local) and bind it to our image
VkMemoryAllocateInfo memAlloc = {};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthStencil.mem));
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0));
// Create a view for the depth stencil image
// Images aren't directly accessed in Vulkan, but rather through views described by a subresource range
// This allows for multiple views of one image with differing ranges (e.g. for different layers)
VkImageViewCreateInfo depthStencilView = {};
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.format = ext::vulkan::swapchain.depthFormat;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;
depthStencilView.image = depthStencil.image;
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view));
// resize attachments if necessary
if ( commandBufferSet ) {
for ( auto& attachment: this->attachments ) {
if ( attachment.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue;
attach( attachment.format, attachment.usage, &attachment );
}
}
// ensure attachments are already created
assert( this->attachments.size() > 0 );
// Create render pass
{
// This example will use a single render pass with one subpass
if ( !renderPass ) {
std::vector<VkAttachmentDescription> attachments; attachments.reserve( this->attachments.size() );
for ( auto& attachment : this->attachments ) {
VkAttachmentDescription description;
description.format = attachment.format;
description.samples = VK_SAMPLE_COUNT_1_BIT;
description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
description.finalLayout = attachment.layout;
// Descriptors for the attachments used by this renderpass
std::array<VkAttachmentDescription, 2> attachments = {};
// Color attachment
attachments[0].format = ext::vulkan::swapchain.colorFormat; // Use the color format selected by the swapchain
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; // We don't use multi sampling in this example
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Clear this attachment at the start of the render pass
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Keep it's contents after the render pass is finished (for displaying it)
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // We don't use stencil, so don't care for load
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // Same for store
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Layout at render pass start. Initial doesn't matter, so we use undefined
attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // Layout to which the attachment is transitioned when the render pass is finished
// As we want to present the color buffer to the swapchain, we transition to PRESENT_KHR
// Depth attachment
attachments[1].format = ext::vulkan::swapchain.depthFormat; // A proper depth format is selected in the example base
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // Clear depth at start of first subpass
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // We don't need depth after render pass has finished (DONT_CARE may result in better performance)
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // No stencil
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // No Stencil
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Layout at render pass start. Initial doesn't matter, so we use undefined
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Transition to depth/stencil attachment
// Setup attachment references
VkAttachmentReference colorReference = {};
colorReference.attachment = 0; // Attachment 0 is color
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // Attachment layout used as color during the subpass
VkAttachmentReference depthReference = {};
depthReference.attachment = 1; // Attachment 1 is color
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // Attachment used as depth/stemcil used during the subpass
VkSubpassDescription subpassDescription = {};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1; // Subpass uses one color attachment
subpassDescription.pColorAttachments = &colorReference; // Reference to the color attachment in slot 0
subpassDescription.pDepthStencilAttachment = &depthReference; // Reference to the depth attachment in slot 1
subpassDescription.inputAttachmentCount = 0; // Input attachments can be used to sample from contents of a previous subpass
subpassDescription.pInputAttachments = nullptr; // (Input attachments not used by this example)
subpassDescription.preserveAttachmentCount = 0; // Preserved attachments can be used to loop (and preserve) attachments through subpasses
subpassDescription.pPreserveAttachments = nullptr; // (Preserve attachments not used by this example)
subpassDescription.pResolveAttachments = nullptr; // Resolve attachments are resolved at the end of a sub pass and can be used for e.g. multi sampling
// Setup subpass dependencies
// These will add the implicit ttachment layout transitionss specified by the attachment descriptions
// The actual usage layout is preserved through the layout specified in the attachment reference
// Each subpass dependency will introduce a memory and execution dependency between the source and dest subpass described by
// srcStageMask, dstStageMask, srcAccessMask, dstAccessMask (and dependencyFlags is set)
// Note: VK_SUBPASS_EXTERNAL is a special constant that refers to all commands executed outside of the actual renderpass)
std::array<VkSubpassDependency, 2> dependencies;
// First dependency at the start of the renderpass
// Does the transition from final to initial layout
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency
dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution depdendency
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; //VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Second dependency at the end the renderpass
// Does the transition from the initial to the final layout
dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the renderpass
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; //VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
/*
std::array<VkSubpassDependency, 3> dependencies;
// First dependency at the start of the renderpass
// Does the transition from final to initial layout
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // Producer of the dependency
dependencies[0].dstSubpass = 0; // Consumer is our single subpass that will wait for the execution depdendency
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Second dependency at the end the renderpass
// Does the transition from the initial to the final layout
dependencies[1].srcSubpass = 0; // Producer of the dependency is our single subpass
dependencies[1].dstSubpass = 1; // Consumer are all commands outside of the renderpass
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[2].srcSubpass = 1; // Producer of the dependency is our single subpass
dependencies[2].dstSubpass = VK_SUBPASS_EXTERNAL; // Consumer are all commands outside of the renderpass
dependencies[2].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[2].dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dependencies[2].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[2].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
*/
// Create the actual renderpass
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size()); // Number of attachments used by this render pass
renderPassInfo.pAttachments = attachments.data(); // Descriptions of the attachments used by the render pass
renderPassInfo.subpassCount = 1; // We only use one subpass in this example
renderPassInfo.pSubpasses = &subpassDescription; // Description of that subpass
renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size()); // Number of subpass dependencies
renderPassInfo.pDependencies = dependencies.data(); // Subpass dependencies used by the render pass
// renderPassInfo.dependencyCount = 0; // Number of subpass dependencies
// renderPassInfo.pDependencies = nullptr; // Subpass dependencies used by the render pass
// OpenVR
VkRenderPassMultiviewCreateInfo renderPassMultiviewCI{};
if ( USEVR ) {
const uint32_t viewMask = 0b00000011;
const uint32_t correlationMask = 0b00000011;
renderPassMultiviewCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
renderPassMultiviewCI.subpassCount = 1;
renderPassMultiviewCI.pViewMasks = &viewMask;
renderPassMultiviewCI.correlationMaskCount = 1;
renderPassMultiviewCI.pCorrelationMasks = &correlationMask;
renderPassInfo.pNext = &renderPassMultiviewCI;
attachments.push_back(description);
}
VK_CHECK_RESULT(vkCreateRenderPass( device, &renderPassInfo, nullptr, &renderPass));
// ensure that the subpasses are already described
assert( passes.size() > 0 );
std::vector<VkSubpassDescription> descriptions;
std::vector<VkSubpassDependency> dependencies;
// dependency: transition from final
VkSubpassDependency dependency;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
size_t i = 0;
for ( auto& pass : passes ) {
VkSubpassDescription description;
// describe renderpass
description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
description.colorAttachmentCount = pass.colors.size();
description.pColorAttachments = &pass.colors[0];
description.pDepthStencilAttachment = &pass.depth;
description.inputAttachmentCount = pass.inputs.size();
description.pInputAttachments = &pass.inputs[0];
description.preserveAttachmentCount = 0;
description.pPreserveAttachments = nullptr;
description.pResolveAttachments = nullptr;
descriptions.push_back(description);
// transition dependency between subpasses
dependency.srcSubpass = dependency.dstSubpass;
dependency.srcStageMask = dependency.dstStageMask;
dependency.srcAccessMask = dependency.dstAccessMask;
dependency.dstSubpass = i++;
dependency.dstStageMask = pass.stage;
dependency.dstAccessMask = pass.access;
dependencies.push_back(dependency);
}
// dependency: transition to final
{
dependency.srcSubpass = dependency.dstSubpass;
dependency.srcStageMask = dependency.dstStageMask;
dependency.srcAccessMask = dependency.dstAccessMask;
dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies.push_back(dependency);
}
std::cout << this << std::endl;
for ( auto& dependency : dependencies ) {
std::cout << "Subpass: " << std::hex << dependency.srcSubpass << " -> " << std::hex << dependency.dstSubpass << std::endl;;
std::cout << "StageMask: " << std::hex << dependency.srcStageMask << " -> " << std::hex << dependency.dstStageMask << std::endl;;
std::cout << "AccessMask: " << std::hex << dependency.srcAccessMask << " -> " << std::hex << dependency.dstAccessMask << std::endl;;
std::cout << std::endl;
}
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.flags = 0;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = &attachments[0];
renderPassInfo.subpassCount = static_cast<uint32_t>(descriptions.size());
renderPassInfo.pSubpasses = &descriptions[0];
renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
renderPassInfo.pDependencies = &dependencies[0];
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass));
}
// Create framebuffer
{
std::vector<VkImageView> attachments;
// attachments[0] = swapchain.buffers[i].view; // Color attachment is the view of the swapchain image
// attachments[1] = depthStencil.view; // Depth/Stencil attachment is the same for all frame buffers
for ( auto attachment : this->attachments ) attachments.push_back(attachment.view);
framebuffers.resize(swapchain.imageCount);
for ( size_t i = 0; i < framebuffers.size(); ++i ) {
std::vector<VkImageView> attachments;
for ( auto& attachment : this->attachments ) {
if ( attachment.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) attachments.push_back(swapchain.buffers[i].view);
else attachments.push_back(attachment.view);
}
VkFramebufferCreateInfo frameBufferCreateInfo = {};
frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
// All frame buffers use the same renderpass setup
frameBufferCreateInfo.renderPass = renderPass;
frameBufferCreateInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
frameBufferCreateInfo.pAttachments = &attachments[0];
frameBufferCreateInfo.width = width;
frameBufferCreateInfo.height = height;
frameBufferCreateInfo.layers = 1;
// Create the framebuffer
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &framebuffer));
VkFramebufferCreateInfo frameBufferCreateInfo = {};
frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
// All frame buffers use the same renderpass setup
frameBufferCreateInfo.renderPass = renderPass;
frameBufferCreateInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
frameBufferCreateInfo.pAttachments = &attachments[0];
frameBufferCreateInfo.width = width;
frameBufferCreateInfo.height = height;
frameBufferCreateInfo.layers = 1;
// Create the framebuffer
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &framebuffers[i]));
}
}
}
void ext::vulkan::RenderTarget::destroy() {
if ( !device ) return;
vkDestroySampler( *device, sampler, nullptr );
vkDestroyRenderPass( *device, renderPass, nullptr );
vkDestroyFramebuffer( *device, framebuffer, nullptr );
for ( auto& framebuffer : framebuffers ) vkDestroyFramebuffer( *device, framebuffer, nullptr );
for ( auto& attachment : attachments ) {
if ( attachment.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue;
vkDestroyImageView( *device, attachment.view, nullptr );
attachment.view = VK_NULL_HANDLE;
vkDestroyImage( *device, attachment.image, nullptr );
attachment.image = VK_NULL_HANDLE;
vkFreeMemory( *device, attachment.mem, nullptr );
attachment.mem = VK_NULL_HANDLE;
}
renderPass = VK_NULL_HANDLE;
framebuffer = VK_NULL_HANDLE;
device = VK_NULL_HANDLE;
}

View File

@ -1,6 +1,7 @@
#include <uf/ext/glfw/glfw.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/vulkan/commands/deferred.h>
#include <fstream>
@ -157,7 +158,12 @@ void ext::vulkan::initialize( uint8_t stage ) {
allocatorInfo.device = device.logicalDevice;
vmaCreateAllocator(&allocatorInfo, &allocator);
}
if ( !ext::vulkan::command ) ext::vulkan::command = ext::vulkan::openvr ? new ext::vulkan::MultiviewCommand() : new ext::vulkan::Command();
if ( !ext::vulkan::command ) {
// ext::vulkan::command = ext::vulkan::openvr ? new ext::vulkan::MultiviewCommand() : new ext::vulkan::Command();
// would ternary but yields "conditional expression between distinct pointer types ext::vulkan::MultiviewCommand* and ext::vulkan::DeferredCommand* lacks a cast"
if ( ext::vulkan::openvr ) ext::vulkan::command = new ext::vulkan::MultiviewCommand();
else ext::vulkan::command = new ext::vulkan::DeferredCommand();
}
ext::vulkan::command->initialize(device);
ext::vulkan::command->createCommandBuffers();