Commit for 2020.07.18.7z
This commit is contained in:
parent
e3e28a8910
commit
e1736f573a
@ -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);
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
10
bin/data/shaders/old/display.frag.glsl
Normal file
10
bin/data/shaders/old/display.frag.glsl
Normal 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);
|
||||
}
|
||||
17
bin/data/shaders/old/display.vert.glsl
Normal file
17
bin/data/shaders/old/display.vert.glsl
Normal 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);
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
24
engine/inc/uf/ext/vulkan/commands/deferred.h
Normal file
24
engine/inc/uf/ext/vulkan/commands/deferred.h
Normal 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,7 @@ namespace ext {
|
||||
} uniforms;
|
||||
|
||||
uint32_t indices = 0;
|
||||
VkSampler sampler;
|
||||
ext::vulkan::RenderTarget* framebuffer;
|
||||
|
||||
virtual void createCommandBuffer( VkCommandBuffer );
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 );
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
217
engine/src/ext/vulkan/commands/deferred.cpp
Normal file
217
engine/src/ext/vulkan/commands/deferred.cpp
Normal 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(¤tBuffer));
|
||||
|
||||
// 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));
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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(¤tBuffer));
|
||||
|
||||
// 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));
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user