Add Offscreen Framebuffer support
This commit is contained in:
@@ -5,3 +5,4 @@ Release/
|
|||||||
*/Release/
|
*/Release/
|
||||||
bin/
|
bin/
|
||||||
.ycm_extra_conf.py
|
.ycm_extra_conf.py
|
||||||
|
.cache
|
||||||
|
|||||||
@@ -130,7 +130,8 @@
|
|||||||
</Command>
|
</Command>
|
||||||
</PreBuildEvent>
|
</PreBuildEvent>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>glslc res/shaders/shader.vert -o res/shaders/vert.spv && glslc res/shaders/shader.frag -o res/shaders/frag.spv</Command>
|
<Command>
|
||||||
|
</Command>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@@ -157,12 +158,14 @@
|
|||||||
</Command>
|
</Command>
|
||||||
</PreBuildEvent>
|
</PreBuildEvent>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>glslc res/shaders/shader.vert -o res/shaders/vert.spv && glslc res/shaders/shader.frag -o res/shaders/frag.spv</Command>
|
<Command>
|
||||||
|
</Command>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\main.cpp" />
|
<ClCompile Include="src\main.cpp" />
|
||||||
<ClCompile Include="src\SwapChain.cpp" />
|
<ClCompile Include="src\SwapChain.cpp" />
|
||||||
|
<ClCompile Include="src\Texture2D.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\Buffer.h" />
|
<ClInclude Include="src\Buffer.h" />
|
||||||
@@ -172,6 +175,7 @@
|
|||||||
<ClInclude Include="src\DescriptorSet.h" />
|
<ClInclude Include="src\DescriptorSet.h" />
|
||||||
<ClInclude Include="src\DescriptorPool.h" />
|
<ClInclude Include="src\DescriptorPool.h" />
|
||||||
<ClInclude Include="src\FileSystem.h" />
|
<ClInclude Include="src\FileSystem.h" />
|
||||||
|
<ClInclude Include="src\Framebuffer.h" />
|
||||||
<ClInclude Include="src\Image.h" />
|
<ClInclude Include="src\Image.h" />
|
||||||
<ClInclude Include="src\IndexBuffer.h" />
|
<ClInclude Include="src\IndexBuffer.h" />
|
||||||
<ClInclude Include="src\Pipeline.h" />
|
<ClInclude Include="src\Pipeline.h" />
|
||||||
@@ -189,13 +193,14 @@
|
|||||||
<ClInclude Include="src\VertexDescriptor.h" />
|
<ClInclude Include="src\VertexDescriptor.h" />
|
||||||
<ClInclude Include="src\VulkanException.h" />
|
<ClInclude Include="src\VulkanException.h" />
|
||||||
<ClInclude Include="src\Window.h" />
|
<ClInclude Include="src\Window.h" />
|
||||||
|
<ClInclude Include="src\VertexPassthrough.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="compile.bat" />
|
<None Include="compile.bat" />
|
||||||
<None Include="res\shaders\frag.spv" />
|
<None Include="res\shaders\passthrough.frag" />
|
||||||
|
<None Include="res\shaders\passthrough.vert" />
|
||||||
<None Include="res\shaders\shader.frag" />
|
<None Include="res\shaders\shader.frag" />
|
||||||
<None Include="res\shaders\shader.vert" />
|
<None Include="res\shaders\shader.vert" />
|
||||||
<None Include="res\shaders\vert.spv" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
<ClCompile Include="src\SwapChain.cpp">
|
<ClCompile Include="src\SwapChain.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Texture2D.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\DebugMessenger.h">
|
<ClInclude Include="src\DebugMessenger.h">
|
||||||
@@ -95,6 +98,12 @@
|
|||||||
<ClInclude Include="src\Image.h">
|
<ClInclude Include="src\Image.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Framebuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\VertexPassthrough.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="res\shaders\shader.frag" />
|
<None Include="res\shaders\shader.frag" />
|
||||||
@@ -102,7 +111,7 @@
|
|||||||
<None Include="compile.bat">
|
<None Include="compile.bat">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</None>
|
</None>
|
||||||
<None Include="res\shaders\frag.spv" />
|
<None Include="res\shaders\passthrough.frag" />
|
||||||
<None Include="res\shaders\vert.spv" />
|
<None Include="res\shaders\passthrough.vert" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform sampler2D texSampler;
|
||||||
|
layout(location = 0) in vec2 fragTexCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outColor = texture(texSampler, fragTexCoord);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inPosition;
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 fragTexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(inPosition* 0.5, 0.999, 1.0);
|
||||||
|
fragTexCoord = inPosition * 0.5 + 0.5;
|
||||||
|
}
|
||||||
@@ -10,6 +10,6 @@ layout(location = 3) in vec3 fragLightPos;
|
|||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float scale = 0.45 + max(dot(vec3(0, 1, 0), normalize(fragLightPos - fragPosition)), 0.0);
|
float scale = 0.45 + max(dot(vec3(0, 1, 0), normalize(fragLightPos - fragPosition)), 0.0);
|
||||||
outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord) * scale;
|
outColor = vec4(fragColor, 1.0) * texture(texSampler, fragTexCoord) * scale;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
layout(set = 0, binding = 0) uniform SceneUniformBufferObject
|
layout(set = 0, binding = 0) uniform SceneUniformBufferObject
|
||||||
{
|
{
|
||||||
mat4 projection;
|
mat4 projection;
|
||||||
mat4 view;
|
mat4 view;
|
||||||
mat4 model;
|
mat4 model;
|
||||||
vec3 lightPos;
|
vec3 lightPos;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
layout(location = 0) in vec3 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
@@ -18,9 +18,9 @@ layout(location = 2) out vec3 fragPosition;
|
|||||||
layout(location = 3) out vec3 fragLightPos;
|
layout(location = 3) out vec3 fragLightPos;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 1.0);
|
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPosition, 1.0);
|
||||||
fragColor = inColor;
|
fragColor = inColor;
|
||||||
fragTexCoord = inTexCoord;
|
fragTexCoord = inTexCoord;
|
||||||
fragPosition = vec3(ubo.model * vec4(inPosition, 1.0));
|
fragPosition = vec3(ubo.model * vec4(inPosition, 1.0));
|
||||||
fragLightPos = ubo.lightPos;
|
fragLightPos = ubo.lightPos;
|
||||||
}
|
}
|
||||||
+1
-1
@@ -100,7 +100,7 @@ public:
|
|||||||
mappedData = nullptr;
|
mappedData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Bind(VkCommandBuffer commandBuffer) { CP_UNIMPLEMENTED(); };
|
virtual void Bind(const CommandBuffer& commandBuffer) { CP_UNIMPLEMENTED(); };
|
||||||
|
|
||||||
void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
|
void BindAsVertexBuffer(VkCommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ public:
|
|||||||
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
|
vkFreeCommandBuffers(instance.GetDevice(), instance.GetCommandPool(), commandBuffers.size(), commandBuffers.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator VkCommandBuffer() const
|
||||||
|
{
|
||||||
|
return currentCommandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Test as constexpr function to see if it avoids the switch case
|
// TODO: Test as constexpr function to see if it avoids the switch case
|
||||||
void Begin()
|
void Begin()
|
||||||
{
|
{
|
||||||
@@ -87,7 +92,7 @@ public:
|
|||||||
instance.SubmitGraphicsQueue({currentCommandBuffer});
|
instance.SubmitGraphicsQueue({currentCommandBuffer});
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer GetHandle()
|
VkCommandBuffer GetHandle() const
|
||||||
{
|
{
|
||||||
return currentCommandBuffer;
|
return currentCommandBuffer;
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-7
@@ -21,11 +21,17 @@
|
|||||||
#define CP_ERR_CONT(format, ...) std::cout << TERM_RED << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
#define CP_ERR_CONT(format, ...) std::cout << TERM_RED << " " << StringFormat(format, __VA_ARGS__) << TERM_CLEAR << std::endl
|
||||||
|
|
||||||
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
|
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
|
||||||
|
#define CP_ABORT(format, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
CP_ERR(format, __VA_ARGS__); \
|
||||||
|
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
|
||||||
|
} while(false)
|
||||||
#define CP_ASSERT(Function, format, ...) \
|
#define CP_ASSERT(Function, format, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
if(!(Function)) \
|
if(!(Function)) \
|
||||||
{ \
|
{ \
|
||||||
CP_ERR(format, __VA_ARGS__); \
|
CP_ERR(format, __VA_ARGS__); \
|
||||||
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
|
throw std::runtime_error(StringFormat(format, __VA_ARGS__)); \
|
||||||
} \
|
} \
|
||||||
@@ -40,16 +46,16 @@
|
|||||||
} \
|
} \
|
||||||
} while(false)
|
} while(false)
|
||||||
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
|
||||||
ClassName(ClassName&&) = delete; \
|
ClassName(ClassName&&) = delete; \
|
||||||
ClassName(const ClassName&) = delete; \
|
ClassName(const ClassName&) = delete; \
|
||||||
ClassName& operator=(ClassName&&) = delete; \
|
ClassName& operator=(ClassName&&) = delete; \
|
||||||
ClassName& operator=(const ClassName&) = delete
|
ClassName& operator=(const ClassName&) = delete
|
||||||
|
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
std::string StringFormat(const std::string& format, Args... args)
|
std::string StringFormat(const std::string& format, Args... args)
|
||||||
{
|
{
|
||||||
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
|
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
|
||||||
CP_ASSERT(size > 0, "Error during formatting");
|
CP_ASSERT(size > 0, "Error during formatting");
|
||||||
std::unique_ptr<char[]> buf(new char[size]);
|
std::unique_ptr<char[]> buf(new char[size]);
|
||||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||||
return std::string(buf.get(), buf.get() + size - 1);
|
return std::string(buf.get(), buf.get() + size - 1);
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ public:
|
|||||||
|
|
||||||
void AddTexture2D(const Texture2D& texture2D, uint32_t binding)
|
void AddTexture2D(const Texture2D& texture2D, uint32_t binding)
|
||||||
{
|
{
|
||||||
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo();
|
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i) {
|
||||||
for (auto&& descriptorSet : descriptorSets) {
|
VkDescriptorImageInfo imageInfo = texture2D.GetDescriptorImageInfo(i);
|
||||||
VkWriteDescriptorSet descriptorWrite{};
|
VkWriteDescriptorSet descriptorWrite{};
|
||||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptorWrite.dstSet = descriptorSet;
|
descriptorWrite.dstSet = descriptorSets[i];
|
||||||
descriptorWrite.dstBinding = binding;
|
descriptorWrite.dstBinding = binding;
|
||||||
descriptorWrite.dstArrayElement = 0;
|
descriptorWrite.dstArrayElement = 0;
|
||||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ namespace FileSystem
|
|||||||
|
|
||||||
static void WriteFile(const std::string& filename, const char* data, size_t size)
|
static void WriteFile(const std::string& filename, const char* data, size_t size)
|
||||||
{
|
{
|
||||||
|
std::filesystem::path path{filename};
|
||||||
|
std::filesystem::create_directories(path.parent_path());
|
||||||
std::ofstream file(filename, std::ios::binary);
|
std::ofstream file(filename, std::ios::binary);
|
||||||
CP_ASSERT(file.is_open(), "Failed to open file");
|
CP_ASSERT(file.is_open(), "Failed to open file");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Image.h"
|
||||||
|
#include "Instance.h"
|
||||||
|
#include "Texture2D.h"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
// TODO: Add resizing (recreate image, depthImage, framebuffers)
|
||||||
|
class Framebuffer
|
||||||
|
{
|
||||||
|
CP_DELETE_COPY_AND_MOVE_CTOR(Framebuffer);
|
||||||
|
private:
|
||||||
|
Instance& instance;
|
||||||
|
|
||||||
|
std::unique_ptr<Texture2D> image;
|
||||||
|
std::unique_ptr<Texture2D> depthImage;
|
||||||
|
std::vector<VkFramebuffer> framebuffers;
|
||||||
|
VkRenderPass renderPass;
|
||||||
|
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
public:
|
||||||
|
Framebuffer(Instance& instance, uint32_t width, uint32_t height)
|
||||||
|
: instance{instance}, width{width}, height{height}
|
||||||
|
{
|
||||||
|
InitializeImages();
|
||||||
|
InitializeDepthBuffer();
|
||||||
|
InitializeRenderPass();
|
||||||
|
InitializeFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Framebuffer()
|
||||||
|
{
|
||||||
|
for (auto& framebuffer : framebuffers)
|
||||||
|
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
||||||
|
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bind(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
std::vector<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.renderPass = renderPass;
|
||||||
|
renderPassBeginInfo.framebuffer = framebuffers[instance.GetFlightIndex()];
|
||||||
|
renderPassBeginInfo.renderArea.offset = {0, 0};
|
||||||
|
renderPassBeginInfo.renderArea.extent = {width, height};
|
||||||
|
renderPassBeginInfo.clearValueCount = clearValues.size();
|
||||||
|
renderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unbind(const CommandBuffer& commandBuffer)
|
||||||
|
{
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPass GetRenderPass() const
|
||||||
|
{
|
||||||
|
return renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkFramebuffer GetFramebuffer() const
|
||||||
|
{
|
||||||
|
return framebuffers[instance.GetFlightIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Texture2D& GetTexture2D() const
|
||||||
|
{
|
||||||
|
return *image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void InitializeImages()
|
||||||
|
{
|
||||||
|
image = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Dynamic, Texture2D::Format::Color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeDepthBuffer()
|
||||||
|
{
|
||||||
|
depthImage = std::make_unique<Texture2D>(instance, width, height, Texture2D::Type::Static, Texture2D::Format::Depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeRenderPass()
|
||||||
|
{
|
||||||
|
VkAttachmentDescription colorAttachment{};
|
||||||
|
colorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
|
||||||
|
VkAttachmentDescription depthAttachment{};
|
||||||
|
depthAttachment.format = Image::SelectDepthFormat(instance);
|
||||||
|
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkAttachmentReference colorAttachmentRef{};
|
||||||
|
colorAttachmentRef.attachment = 0;
|
||||||
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkAttachmentReference depthAttachmentRef{};
|
||||||
|
depthAttachmentRef.attachment = 1;
|
||||||
|
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass{};
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &colorAttachmentRef;
|
||||||
|
subpass.pDepthStencilAttachment = &depthAttachmentRef;
|
||||||
|
|
||||||
|
std::vector<VkSubpassDependency> dependencies{2};
|
||||||
|
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
|
dependencies[0].dstSubpass = 0;
|
||||||
|
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
dependencies[1].srcSubpass = 0;
|
||||||
|
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::vector<VkAttachmentDescription> attachments{colorAttachment, depthAttachment};
|
||||||
|
VkRenderPassCreateInfo renderPassCreateInfo{};
|
||||||
|
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderPassCreateInfo.attachmentCount = attachments.size();
|
||||||
|
renderPassCreateInfo.pAttachments = attachments.data();
|
||||||
|
renderPassCreateInfo.subpassCount = 1;
|
||||||
|
renderPassCreateInfo.pSubpasses = &subpass;
|
||||||
|
renderPassCreateInfo.dependencyCount = dependencies.size();
|
||||||
|
renderPassCreateInfo.pDependencies = dependencies.data();
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateRenderPass(instance.GetDevice(), &renderPassCreateInfo, nullptr, &renderPass), "InitializeRenderPass : Failed to initialze render pass");
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeFramebuffers()
|
||||||
|
{
|
||||||
|
framebuffers.resize(instance.GetMaxFramesInFlight());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < instance.GetMaxFramesInFlight(); ++i)
|
||||||
|
{
|
||||||
|
std::vector<VkImageView> attachments{image->GetImageView(i), depthImage->GetImageView()};
|
||||||
|
|
||||||
|
VkFramebufferCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
createInfo.renderPass = renderPass;
|
||||||
|
createInfo.attachmentCount = attachments.size();
|
||||||
|
createInfo.pAttachments = attachments.data();
|
||||||
|
createInfo.width = width;
|
||||||
|
createInfo.height = height;
|
||||||
|
createInfo.layers = 1;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateFramebuffer(instance.GetDevice(), &createInfo, nullptr, &framebuffers[i]), "InitializeFramebuffers : Failed to initialize swap chain framebuffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
+37
-6
@@ -28,7 +28,7 @@ public:
|
|||||||
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
createInfo.flags = 0;
|
createInfo.flags = 0;
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateImage(instance.GetDevice(), &createInfo, nullptr, image), "Failed to initialize image");
|
CP_VK_ASSERT(vkCreateImage(instance.GetDevice(), &createInfo, nullptr, image), "InitializeImage : Failed to initialize image");
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements;
|
VkMemoryRequirements memoryRequirements;
|
||||||
vkGetImageMemoryRequirements(instance.GetDevice(), *image, &memoryRequirements);
|
vkGetImageMemoryRequirements(instance.GetDevice(), *image, &memoryRequirements);
|
||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
allocateInfo.allocationSize = memoryRequirements.size;
|
||||||
allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
|
allocateInfo.memoryTypeIndex = instance.FindMemoryType(memoryRequirements.memoryTypeBits, properties);
|
||||||
|
|
||||||
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, imageMemory), "Failed to initiallizse image memory");
|
CP_VK_ASSERT(vkAllocateMemory(instance.GetDevice(), &allocateInfo, nullptr, imageMemory), "InitializeImage : Failed to initiallizse image memory");
|
||||||
|
|
||||||
vkBindImageMemory(instance.GetDevice(), *image, *imageMemory, 0);
|
vkBindImageMemory(instance.GetDevice(), *image, *imageMemory, 0);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
createInfo.subresourceRange.levelCount = 1;
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
createInfo.subresourceRange.layerCount = 1;
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "Failed to initialize image view");
|
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "InitializeImageView : Failed to initialize image view");
|
||||||
return imageView;
|
return imageView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,12 +115,19 @@ public:
|
|||||||
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
}
|
}
|
||||||
|
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::invalid_argument("Unsupported layout transition");
|
CP_ABORT("TransitioinImageLayout : Unsupported layout transition");
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdPipelineBarrier(commandBuffer.GetHandle(), srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
vkCmdPipelineBarrier(commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyBufferToImage(Instance& instance, const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
|
static void CopyBufferToImage(Instance& instance, const Buffer& buffer, VkImage image, uint32_t width, uint32_t height)
|
||||||
@@ -140,7 +147,13 @@ public:
|
|||||||
region.imageOffset = {0, 0, 0};
|
region.imageOffset = {0, 0, 0};
|
||||||
region.imageExtent = {width, height, 1};
|
region.imageExtent = {width, height, 1};
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(commandBuffer.GetHandle(), buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(commandBuffer, buffer.GetHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VkFormat SelectDepthFormat(Instance& instance)
|
||||||
|
{
|
||||||
|
return SelectSupportedFormat(instance, {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -148,4 +161,22 @@ private:
|
|||||||
{
|
{
|
||||||
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
|
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VkFormat SelectSupportedFormat(Instance& instance, const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
|
||||||
|
{
|
||||||
|
for (VkFormat format : candidates)
|
||||||
|
{
|
||||||
|
VkFormatProperties properties;
|
||||||
|
vkGetPhysicalDeviceFormatProperties(instance.GetPhysicalDevice(), format, &properties);
|
||||||
|
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features)
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features)
|
||||||
|
{
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CP_ABORT("SelectSupportedFormat : Failed to select supported format");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -12,12 +12,12 @@ public:
|
|||||||
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount}
|
: Buffer{instance, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexCount * sizeof(uint16_t), 1}, indexCount{indexCount}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void Bind(VkCommandBuffer commandBuffer) override
|
void Bind(const CommandBuffer& commandBuffer) override
|
||||||
{
|
{
|
||||||
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
vkCmdBindIndexBuffer(commandBuffer, handle, 0, VK_INDEX_TYPE_UINT16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(VkCommandBuffer commandBuffer)
|
void Draw(const CommandBuffer& commandBuffer)
|
||||||
{
|
{
|
||||||
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "CommandBuffer.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "DescriptorSet.h"
|
#include "DescriptorSet.h"
|
||||||
@@ -40,7 +41,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bind(VkCommandBuffer commandBuffer)
|
void Bind(const CommandBuffer& commandBuffer)
|
||||||
{
|
{
|
||||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ private:
|
|||||||
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
|
graphicsPipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
|
||||||
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
|
||||||
graphicsPipelineCreateInfo.layout = pipelineLayout;
|
graphicsPipelineCreateInfo.layout = pipelineLayout;
|
||||||
graphicsPipelineCreateInfo.renderPass = instance.GetSwapChain().GetRenderPass();
|
graphicsPipelineCreateInfo.renderPass = creator.renderPass;
|
||||||
graphicsPipelineCreateInfo.subpass = 0;
|
graphicsPipelineCreateInfo.subpass = 0;
|
||||||
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
|
graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
graphicsPipelineCreateInfo.basePipelineIndex = -1;
|
graphicsPipelineCreateInfo.basePipelineIndex = -1;
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ private:
|
|||||||
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PipelineCreator(const std::string& vertexShader, const std::string& fragmentShader)
|
PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader)
|
||||||
: vertexShader{vertexShader}, fragmentShader{fragmentShader}
|
: vertexShader{vertexShader}, fragmentShader{fragmentShader}, renderPass{renderPass}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SetVertexDescriptor(const VertexDescriptor& descriptor)
|
void SetVertexDescriptor(const VertexDescriptor& descriptor)
|
||||||
@@ -38,7 +39,7 @@ public:
|
|||||||
|
|
||||||
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags)
|
void AddDescriptorSetLayoutBinding(uint32_t set, uint32_t binding, VkDescriptorType type, uint32_t count, VkShaderStageFlags stageFlags)
|
||||||
{
|
{
|
||||||
CP_ASSERT(set <= descriptorSetLayouts.size(), "Cannot add descriptor set with set number greater than the current set count");
|
CP_ASSERT(set <= descriptorSetLayouts.size(), "AddDescriptorSetLayoutBinding : Cannot add descriptor set with set number greater than the current set count");
|
||||||
descriptorSetLayouts[set].emplace_back(DescriptorSetBinding{binding, type, count, stageFlags});
|
descriptorSetLayouts[set].emplace_back(DescriptorSetBinding{binding, type, count, stageFlags});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -89,7 +89,7 @@ private:
|
|||||||
|
|
||||||
VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind shaderType)
|
VkShaderModule InitializeShaderModuleFromGlslFile(const std::string& filename, shaderc_shader_kind shaderType)
|
||||||
{
|
{
|
||||||
std::string spvFilename = filename + ".spv";
|
std::string spvFilename = ".cache/" + filename + ".spv";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (FileSystem::FileExists(spvFilename))
|
if (FileSystem::FileExists(spvFilename))
|
||||||
|
|||||||
+27
-33
@@ -1,8 +1,10 @@
|
|||||||
#include "SwapChain.h"
|
#include "SwapChain.h"
|
||||||
|
|
||||||
|
#include "CommandBuffer.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "QueueFamilies.h"
|
#include "QueueFamilies.h"
|
||||||
|
#include "Texture2D.h"
|
||||||
|
|
||||||
#include <glfw/glfw3.h>
|
#include <glfw/glfw3.h>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
@@ -50,6 +52,28 @@ SwapChain::~SwapChain()
|
|||||||
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
|
vkDestroyRenderPass(instance.GetDevice(), renderPass, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwapChain::BeginFrameBuffer(const CommandBuffer& commandBuffer) const
|
||||||
|
{
|
||||||
|
std::vector<VkClearValue> clearValues{2};
|
||||||
|
clearValues[0].color = {{0.02f, 0.02f, 0.02f, 1.0f}};
|
||||||
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
|
|
||||||
|
VkRenderPassBeginInfo renderPassBeginInfo{};
|
||||||
|
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
renderPassBeginInfo.renderPass = renderPass;
|
||||||
|
renderPassBeginInfo.framebuffer = framebuffers[imageIndex];
|
||||||
|
renderPassBeginInfo.renderArea.offset = {0, 0};
|
||||||
|
renderPassBeginInfo.renderArea.extent = extent;
|
||||||
|
renderPassBeginInfo.clearValueCount = clearValues.size();
|
||||||
|
renderPassBeginInfo.pClearValues = clearValues.data();
|
||||||
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::EndFrameBuffer(const CommandBuffer& commandBuffer) const
|
||||||
|
{
|
||||||
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
VkSwapchainKHR SwapChain::GetHandle() const
|
VkSwapchainKHR SwapChain::GetHandle() const
|
||||||
{
|
{
|
||||||
return handle;
|
return handle;
|
||||||
@@ -182,11 +206,7 @@ void SwapChain::InitializeImageViews()
|
|||||||
|
|
||||||
void SwapChain::InitializeDepthBuffer()
|
void SwapChain::InitializeDepthBuffer()
|
||||||
{
|
{
|
||||||
VkFormat depthFormat = SelectDepthFormat();
|
depthImage = std::make_unique<Texture2D>(instance, extent.width, extent.height, Texture2D::Type::Static, Texture2D::Format::Depth);
|
||||||
Image::InitializeImage(instance, extent.width, extent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &depthImage, &depthImageMemory);
|
|
||||||
Image::TransitionImageLayout(instance, depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
|
||||||
|
|
||||||
depthImageView = Image::InitializeImageView(instance, depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapChain::InitializeRenderPass()
|
void SwapChain::InitializeRenderPass()
|
||||||
@@ -202,7 +222,7 @@ void SwapChain::InitializeRenderPass()
|
|||||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
VkAttachmentDescription depthAttachment{};
|
VkAttachmentDescription depthAttachment{};
|
||||||
depthAttachment.format = SelectDepthFormat();
|
depthAttachment.format = Image::SelectDepthFormat(instance);
|
||||||
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
@@ -252,7 +272,7 @@ void SwapChain::InitializeFramebuffers()
|
|||||||
|
|
||||||
for (size_t i = 0; i < imageViews.size(); ++i)
|
for (size_t i = 0; i < imageViews.size(); ++i)
|
||||||
{
|
{
|
||||||
std::vector<VkImageView> attachments{imageViews[i], depthImageView};
|
std::vector<VkImageView> attachments{imageViews[i], depthImage->GetImageView()};
|
||||||
|
|
||||||
VkFramebufferCreateInfo createInfo{};
|
VkFramebufferCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
@@ -269,9 +289,6 @@ void SwapChain::InitializeFramebuffers()
|
|||||||
|
|
||||||
void SwapChain::Destroy()
|
void SwapChain::Destroy()
|
||||||
{
|
{
|
||||||
vkDestroyImage(instance.GetDevice(), depthImage, nullptr);
|
|
||||||
vkFreeMemory(instance.GetDevice(), depthImageMemory, nullptr);
|
|
||||||
vkDestroyImageView(instance.GetDevice(), depthImageView, nullptr);
|
|
||||||
for (auto&& framebuffer : framebuffers)
|
for (auto&& framebuffer : framebuffers)
|
||||||
{
|
{
|
||||||
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
vkDestroyFramebuffer(instance.GetDevice(), framebuffer, nullptr);
|
||||||
@@ -295,29 +312,6 @@ VkSurfaceFormatKHR SwapChain::SelectSwapSurfaceFormat(const std::vector<VkSurfac
|
|||||||
return availableFormats[0];
|
return availableFormats[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFormat SwapChain::SelectDepthFormat()
|
|
||||||
{
|
|
||||||
return SelectSupportedFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFormat SwapChain::SelectSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
|
|
||||||
{
|
|
||||||
for (VkFormat format : candidates)
|
|
||||||
{
|
|
||||||
VkFormatProperties properties;
|
|
||||||
vkGetPhysicalDeviceFormatProperties(instance.GetPhysicalDevice(), format, &properties);
|
|
||||||
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features)
|
|
||||||
{
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features)
|
|
||||||
{
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw std::runtime_error("Failed to select supported format");
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
VkPresentModeKHR SwapChain::SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
||||||
{
|
{
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
|
class CommandBuffer;
|
||||||
|
class Texture2D;
|
||||||
|
|
||||||
struct SwapChainSupportDetails
|
struct SwapChainSupportDetails
|
||||||
{
|
{
|
||||||
@@ -24,24 +26,22 @@ class SwapChain final
|
|||||||
private:
|
private:
|
||||||
Instance& instance;
|
Instance& instance;
|
||||||
|
|
||||||
// Created by the class
|
|
||||||
VkSwapchainKHR handle;
|
VkSwapchainKHR handle;
|
||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
VkFormat imageFormat;
|
VkFormat imageFormat;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
VkImage depthImage;
|
std::unique_ptr<Texture2D> depthImage;
|
||||||
VkImageView depthImageView;
|
|
||||||
VkDeviceMemory depthImageMemory;
|
|
||||||
std::vector<VkImageView> imageViews;
|
std::vector<VkImageView> imageViews;
|
||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
std::vector<VkFramebuffer> framebuffers;
|
std::vector<VkFramebuffer> framebuffers;
|
||||||
|
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SwapChain(Instance& instance);
|
SwapChain(Instance& instance);
|
||||||
~SwapChain();
|
~SwapChain();
|
||||||
|
|
||||||
|
void BeginFrameBuffer(const CommandBuffer& commandBuffer) const;
|
||||||
|
void EndFrameBuffer(const CommandBuffer& commandBuffer) const;
|
||||||
VkSwapchainKHR GetHandle() const;
|
VkSwapchainKHR GetHandle() const;
|
||||||
VkRenderPass GetRenderPass() const;
|
VkRenderPass GetRenderPass() const;
|
||||||
VkExtent2D GetExtent() const;
|
VkExtent2D GetExtent() const;
|
||||||
@@ -60,8 +60,6 @@ private:
|
|||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
VkSurfaceFormatKHR SelectSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||||
VkFormat SelectDepthFormat();
|
|
||||||
VkFormat SelectSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
|
||||||
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
VkPresentModeKHR SelectSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
||||||
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
|
VkExtent2D SelectSwapExtent(GLFWwindow* window, const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
#include "Texture2D.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include <stb/stb_image.h>
|
||||||
|
|
||||||
|
Texture2D::Texture2D(Instance& instance, const std::string& filename)
|
||||||
|
: instance{instance}, type{Type::Static}, format{Format::Image}
|
||||||
|
{
|
||||||
|
InitializeTextureImage(filename);
|
||||||
|
InitializeSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D::Texture2D(Instance& instance, int width, int height, Type type, Format format)
|
||||||
|
: instance{instance}, type{type}, format{format}
|
||||||
|
{
|
||||||
|
InitializeTexture(width, height);
|
||||||
|
InitializeSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D::~Texture2D()
|
||||||
|
{
|
||||||
|
for(auto&& image : images)
|
||||||
|
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
||||||
|
for(auto&& imageMemory : imageMemories)
|
||||||
|
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
||||||
|
for(auto&& imageView : imageViews)
|
||||||
|
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
||||||
|
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const
|
||||||
|
{
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfo.sampler = sampler;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case Type::Static:
|
||||||
|
imageInfo.imageView = imageViews.front();
|
||||||
|
break;
|
||||||
|
case Type::Dynamic:
|
||||||
|
CP_ASSERT(index >= 0 && index < imageViews.size(), "GetDescriptorImageInfo : index out of bound for dynamic texture");
|
||||||
|
imageInfo.imageView = imageViews[index];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CP_ABORT("GetDescriptorImageInfo : Unreachable switch case");
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView Texture2D::GetImageView() const
|
||||||
|
{
|
||||||
|
CP_ASSERT(type == Type::Static, "GetImageView : Texture2D is not static");
|
||||||
|
return imageViews.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageView Texture2D::GetImageView(int index)
|
||||||
|
{
|
||||||
|
CP_ASSERT(type == Type::Dynamic && index >= 0 && index < imageViews.size(), "GetImageView : Texture2D is not dynamic or index out of bound for SystemTexture");
|
||||||
|
return imageViews[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::InitializeTextureImage(const std::string& filename)
|
||||||
|
{
|
||||||
|
int texWidth;
|
||||||
|
int texHeight;
|
||||||
|
int texChannels;
|
||||||
|
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
|
|
||||||
|
CP_ASSERT(pixels, "InitializeTextureImage : Failed to load texture image");
|
||||||
|
|
||||||
|
VkDeviceSize bufferSize = texWidth * texHeight * 4;
|
||||||
|
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
||||||
|
void* data = stagingBuffer.Map();
|
||||||
|
memcpy(data, pixels, bufferSize);
|
||||||
|
stagingBuffer.Unmap();
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
images.resize(1);
|
||||||
|
imageMemories.resize(1);
|
||||||
|
imageViews.resize(1);
|
||||||
|
Image::InitializeImage(instance, texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images.front(), &imageMemories.front());
|
||||||
|
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
Image::CopyBufferToImage(instance, stagingBuffer, images.front(), texWidth, texHeight);
|
||||||
|
Image::TransitionImageLayout(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
imageViews[0] = Image::InitializeImageView(instance, images.front(), VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::InitializeTexture(int width, int height)
|
||||||
|
{
|
||||||
|
int count = 1;
|
||||||
|
if (type == Type::Dynamic)
|
||||||
|
count = instance.GetMaxFramesInFlight();
|
||||||
|
images.resize(count);
|
||||||
|
imageMemories.resize(count);
|
||||||
|
imageViews.resize(count);
|
||||||
|
for (size_t i = 0; i < images.size(); i++)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case Format::Color:
|
||||||
|
{
|
||||||
|
Image::InitializeImage(instance, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
|
||||||
|
// Image::TransitionImageLayout(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
imageViews[i] = Image::InitializeImageView(instance, images[i], VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Format::Depth:
|
||||||
|
{
|
||||||
|
VkFormat depthFormat = Image::SelectDepthFormat(instance);
|
||||||
|
Image::InitializeImage(instance, width, height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &images[i], &imageMemories[i]);
|
||||||
|
// Image::TransitionImageLayout(instance, images[i], depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
imageViews[i] = Image::InitializeImageView(instance, images[i], depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Format::Image:
|
||||||
|
{
|
||||||
|
CP_ABORT("InitializeTexture : Image format currently not supported");
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
CP_ABORT("InitializeTexture : Unreachable switch case");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::InitializeSampler()
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceProperties properties{};
|
||||||
|
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
|
||||||
|
|
||||||
|
VkSamplerCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
createInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
createInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||||
|
createInfo.anisotropyEnable = VK_TRUE;
|
||||||
|
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
||||||
|
createInfo.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
createInfo.compareEnable = VK_FALSE;
|
||||||
|
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
createInfo.mipLodBias = 0.0f;
|
||||||
|
createInfo.minLod = 0.0f;
|
||||||
|
createInfo.maxLod = 0.0f;
|
||||||
|
|
||||||
|
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &sampler), "InitializeSampler : Failed to initialize texture sampler");
|
||||||
|
}
|
||||||
+25
-95
@@ -6,110 +6,40 @@
|
|||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
// TODO: Separate Texture2D and Framebuffer Attachments
|
||||||
#include <stb/stb_image.h>
|
|
||||||
|
|
||||||
class Texture2D
|
class Texture2D
|
||||||
{
|
{
|
||||||
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
|
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Static, Dynamic
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Format
|
||||||
|
{
|
||||||
|
Image, Color, Depth
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
Instance& instance;
|
Instance& instance;
|
||||||
|
|
||||||
VkImage image;
|
std::vector<VkImage> images;
|
||||||
VkDeviceMemory imageMemory;
|
std::vector<VkDeviceMemory> imageMemories;
|
||||||
VkImageView imageView;
|
std::vector<VkImageView> imageViews;
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
|
Type type;
|
||||||
|
Format format;
|
||||||
public:
|
public:
|
||||||
Texture2D(Instance& instance, const std::string& filename)
|
Texture2D(Instance& instance, const std::string& filename);
|
||||||
: instance{instance}
|
Texture2D(Instance& instance, int width, int height, Type type, Format format);
|
||||||
{
|
~Texture2D();
|
||||||
InitializeTextureImage(filename);
|
|
||||||
InitializeSampler();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Texture2D()
|
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const;
|
||||||
{
|
VkImageView GetImageView() const;
|
||||||
vkDestroyImage(instance.GetDevice(), image, nullptr);
|
VkImageView GetImageView(int index);
|
||||||
vkFreeMemory(instance.GetDevice(), imageMemory, nullptr);
|
|
||||||
vkDestroyImageView(instance.GetDevice(), imageView, nullptr);
|
|
||||||
vkDestroySampler(instance.GetDevice(), sampler, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorImageInfo GetDescriptorImageInfo() const
|
|
||||||
{
|
|
||||||
VkDescriptorImageInfo imageInfo{};
|
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
imageInfo.imageView = imageView;
|
|
||||||
imageInfo.sampler = sampler;
|
|
||||||
|
|
||||||
return imageInfo;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
void InitializeTextureImage(const std::string& filename)
|
void InitializeTextureImage(const std::string& filename);
|
||||||
{
|
void InitializeTexture(int width, int height);
|
||||||
int texWidth;
|
void InitializeSampler();
|
||||||
int texHeight;
|
|
||||||
int texChannels;
|
|
||||||
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
CP_ASSERT(pixels, "Failed to load texture image");
|
|
||||||
|
|
||||||
VkDeviceSize bufferSize = texWidth * texHeight * 4;
|
|
||||||
Buffer stagingBuffer{instance, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
|
||||||
void* data = stagingBuffer.Map();
|
|
||||||
memcpy(data, pixels, bufferSize);
|
|
||||||
stagingBuffer.Unmap();
|
|
||||||
stbi_image_free(pixels);
|
|
||||||
|
|
||||||
Image::InitializeImage(instance, texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
|
|
||||||
Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
Image::CopyBufferToImage(instance, stagingBuffer, image, texWidth, texHeight);
|
|
||||||
Image::TransitionImageLayout(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
imageView = Image::InitializeImageView(instance, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeSampler()
|
|
||||||
{
|
|
||||||
VkPhysicalDeviceProperties properties{};
|
|
||||||
vkGetPhysicalDeviceProperties(instance.GetPhysicalDevice(), &properties);
|
|
||||||
|
|
||||||
VkSamplerCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
createInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
createInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
createInfo.anisotropyEnable = VK_TRUE;
|
|
||||||
createInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
|
||||||
createInfo.unnormalizedCoordinates = VK_FALSE;
|
|
||||||
createInfo.compareEnable = VK_FALSE;
|
|
||||||
createInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
createInfo.mipLodBias = 0.0f;
|
|
||||||
createInfo.minLod = 0.0f;
|
|
||||||
createInfo.maxLod = 0.0f;
|
|
||||||
|
|
||||||
CP_VK_ASSERT(vkCreateSampler(instance.GetDevice(), &createInfo, nullptr, &sampler), "Failed to initialize texture sampler");
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView CreateImageView(VkImage image)
|
|
||||||
{
|
|
||||||
VkImageView imageView;
|
|
||||||
VkImageViewCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
createInfo.image = image;
|
|
||||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
createInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
|
||||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
createInfo.subresourceRange.baseMipLevel = 0;
|
|
||||||
createInfo.subresourceRange.levelCount = 1;
|
|
||||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
|
||||||
createInfo.subresourceRange.layerCount = 1;
|
|
||||||
CP_VK_ASSERT(vkCreateImageView(instance.GetDevice(), &createInfo, nullptr, &imageView), "Failed to initialize ImageView");
|
|
||||||
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bind(VkCommandBuffer commandBuffer) override
|
void Bind(const CommandBuffer& commandBuffer) override
|
||||||
{
|
{
|
||||||
std::vector<VkBuffer> buffers{bindingOffsets.size(), handle};
|
std::vector<VkBuffer> buffers{bindingOffsets.size(), handle};
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data());
|
vkCmdBindVertexBuffers(commandBuffer, 0, bindingOffsets.size(), buffers.data(), bindingOffsets.data());
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include "VertexDescriptor.h"
|
||||||
|
|
||||||
|
struct VertexPassthrough {
|
||||||
|
glm::vec2 texCoord;
|
||||||
|
|
||||||
|
static VertexDescriptor GetDescriptor()
|
||||||
|
{
|
||||||
|
VertexDescriptor descriptor{};
|
||||||
|
descriptor.AddAttribute<VertexPassthrough>(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(VertexPassthrough , texCoord));
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
};
|
||||||
+72
-40
@@ -1,6 +1,7 @@
|
|||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "DescriptorPool.h"
|
#include "DescriptorPool.h"
|
||||||
#include "DescriptorSet.h"
|
#include "DescriptorSet.h"
|
||||||
|
#include "Framebuffer.h"
|
||||||
#include "IndexBuffer.h"
|
#include "IndexBuffer.h"
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "Pipeline.h"
|
#include "Pipeline.h"
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
#include "UniformBuffer.h"
|
#include "UniformBuffer.h"
|
||||||
#include "Vertex.h"
|
#include "Vertex.h"
|
||||||
#include "VertexBuffer.h"
|
#include "VertexBuffer.h"
|
||||||
|
#include "VertexPassthrough.h"
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -20,13 +22,13 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
const std::vector<Vertex> vertices = {
|
const std::vector<Vertex> vertices = {
|
||||||
Vertex{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
Vertex{{-0.5f, 0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||||
Vertex{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
Vertex{{ 0.5f, 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||||
Vertex{{ 0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
Vertex{{ 0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||||
Vertex{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
Vertex{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
||||||
Vertex{{-0.5f, 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
Vertex{{-0.5f, 0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||||
Vertex{{ 0.5f, 0.0f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
Vertex{{ 0.5f, 0.0f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||||
Vertex{{ 0.5f, 0.0f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
Vertex{{ 0.5f, 0.0f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||||
Vertex{{-0.5f, 0.0f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
Vertex{{-0.5f, 0.0f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,6 +37,17 @@ const std::vector<uint16_t> indices = {
|
|||||||
4, 5, 6, 6, 7, 4
|
4, 5, 6, 6, 7, 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const std::vector<VertexPassthrough> verticesPassthrough = {
|
||||||
|
VertexPassthrough{{-1.0f, -1.0f}},
|
||||||
|
VertexPassthrough{{ 1.0f, -1.0f}},
|
||||||
|
VertexPassthrough{{ 1.0f, 1.0f}},
|
||||||
|
VertexPassthrough{{-1.0f, 1.0f}},
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<uint16_t> indicesPassthrough = {
|
||||||
|
0, 1, 2, 2, 3, 0,
|
||||||
|
};
|
||||||
|
|
||||||
struct alignas(64) ShaderUniform
|
struct alignas(64) ShaderUniform
|
||||||
{
|
{
|
||||||
alignas(16) glm::mat4 projection;
|
alignas(16) glm::mat4 projection;
|
||||||
@@ -56,10 +69,17 @@ private:
|
|||||||
std::unique_ptr<IndexBuffer> indexBuffer;
|
std::unique_ptr<IndexBuffer> indexBuffer;
|
||||||
std::unique_ptr<CommandBuffer> commandBuffer;
|
std::unique_ptr<CommandBuffer> commandBuffer;
|
||||||
|
|
||||||
|
std::unique_ptr<Framebuffer> framebuffer;
|
||||||
|
std::unique_ptr<Pipeline> graphicsPipelinePassthrough;
|
||||||
|
std::unique_ptr<VertexBuffer> vertexBufferPassthrough;
|
||||||
|
std::unique_ptr<IndexBuffer> indexBufferPassthrough;
|
||||||
|
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application()
|
Application()
|
||||||
{
|
{
|
||||||
InitializeInstance();
|
InitializeInstance();
|
||||||
|
InitializeFrameBuffer();
|
||||||
InitializeGraphicsPipeline();
|
InitializeGraphicsPipeline();
|
||||||
InitializeTextureSampler();
|
InitializeTextureSampler();
|
||||||
InitializeUniformBuffer();
|
InitializeUniformBuffer();
|
||||||
@@ -94,7 +114,12 @@ private:
|
|||||||
|
|
||||||
void InitializeInstance()
|
void InitializeInstance()
|
||||||
{
|
{
|
||||||
instance = std::make_unique<Instance>("Vulkan Tutorial");
|
instance = std::make_unique<Instance>("Copium Engine");
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeFrameBuffer()
|
||||||
|
{
|
||||||
|
framebuffer = std::make_unique<Framebuffer>(*instance, instance->GetSwapChain().GetExtent().width, instance->GetSwapChain().GetExtent().height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeTextureSampler()
|
void InitializeTextureSampler()
|
||||||
@@ -114,30 +139,44 @@ private:
|
|||||||
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
|
descriptorSet = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0));
|
||||||
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
|
descriptorSet->AddUniform(*shaderUniformBuffer, 0);
|
||||||
descriptorSet->AddTexture2D(*texture2D, 1);
|
descriptorSet->AddTexture2D(*texture2D, 1);
|
||||||
|
|
||||||
|
descriptorSetPassthrough = std::make_unique<DescriptorSet>(*instance, *descriptorPool, graphicsPipelinePassthrough->GetDescriptorSetLayout(0));
|
||||||
|
descriptorSetPassthrough->AddTexture2D(framebuffer->GetTexture2D(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeGraphicsPipeline()
|
void InitializeGraphicsPipeline()
|
||||||
{
|
{
|
||||||
PipelineCreator creator{"res/shaders/shader.vert", "res/shaders/shader.frag"};
|
PipelineCreator creator{framebuffer->GetRenderPass(), "res/shaders/shader.vert", "res/shaders/shader.frag"};
|
||||||
creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
creator.AddDescriptorSetLayoutBinding(0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
creator.AddDescriptorSetLayoutBinding(0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
creator.SetVertexDescriptor(Vertex::GetDescriptor());
|
creator.SetVertexDescriptor(Vertex::GetDescriptor());
|
||||||
creator.SetCullMode(VK_CULL_MODE_NONE);
|
creator.SetCullMode(VK_CULL_MODE_NONE);
|
||||||
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
graphicsPipeline = std::make_unique<Pipeline>(*instance, creator);
|
||||||
|
|
||||||
|
PipelineCreator creatorPassthrough{instance->GetSwapChain().GetRenderPass(), "res/shaders/passthrough.vert", "res/shaders/passthrough.frag"};
|
||||||
|
creatorPassthrough.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
creatorPassthrough.SetVertexDescriptor(VertexPassthrough::GetDescriptor());
|
||||||
|
creatorPassthrough.SetCullMode(VK_CULL_MODE_NONE);
|
||||||
|
graphicsPipelinePassthrough = std::make_unique<Pipeline>(*instance, creatorPassthrough);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeVertexBuffer()
|
void InitializeVertexBuffer()
|
||||||
{
|
{
|
||||||
vertexBuffer = std::make_unique<VertexBuffer>(*instance, Vertex::GetDescriptor(), vertices.size());
|
vertexBuffer = std::make_unique<VertexBuffer>(*instance, Vertex::GetDescriptor(), vertices.size());
|
||||||
vertexBuffer->Update(0, (void*)vertices.data());
|
vertexBuffer->Update(0, (void*)vertices.data());
|
||||||
}
|
|
||||||
|
vertexBufferPassthrough = std::make_unique<VertexBuffer>(*instance, VertexPassthrough::GetDescriptor(), verticesPassthrough.size());
|
||||||
|
vertexBufferPassthrough->Update(0, (void*)verticesPassthrough.data());
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeIndexBuffer()
|
void InitializeIndexBuffer()
|
||||||
{
|
{
|
||||||
VkDeviceSize bufferSize = sizeof(uint16_t) * indices.size();
|
|
||||||
indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size());
|
indexBuffer = std::make_unique<IndexBuffer>(*instance, indices.size());
|
||||||
indexBuffer->UpdateStaging((void*)indices.data());
|
indexBuffer->UpdateStaging((void*)indices.data());
|
||||||
}
|
|
||||||
|
indexBufferPassthrough = std::make_unique<IndexBuffer>(*instance, indicesPassthrough.size());
|
||||||
|
indexBufferPassthrough->UpdateStaging((void*)indicesPassthrough.data());
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeCommandBuffer()
|
void InitializeCommandBuffer()
|
||||||
{
|
{
|
||||||
@@ -151,30 +190,32 @@ private:
|
|||||||
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
clearValues[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||||
clearValues[1].depthStencil = {1.0f, 0};
|
clearValues[1].depthStencil = {1.0f, 0};
|
||||||
|
|
||||||
// TODO: framebuffer->Bind();
|
|
||||||
VkRenderPassBeginInfo renderPassBeginInfo{};
|
|
||||||
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
||||||
renderPassBeginInfo.renderPass = instance->GetSwapChain().GetRenderPass();
|
|
||||||
renderPassBeginInfo.framebuffer = instance->GetSwapChain().GetFramebuffer();
|
|
||||||
renderPassBeginInfo.renderArea.offset = {0, 0};
|
|
||||||
renderPassBeginInfo.renderArea.extent = instance->GetSwapChain().GetExtent();
|
|
||||||
renderPassBeginInfo.clearValueCount = clearValues.size();
|
|
||||||
renderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
vkCmdBeginRenderPass(commandBuffer->GetHandle(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
|
|
||||||
graphicsPipeline->Bind(commandBuffer->GetHandle());
|
|
||||||
|
framebuffer->Bind(*commandBuffer);
|
||||||
|
graphicsPipeline->Bind(*commandBuffer);
|
||||||
|
|
||||||
UpdateUniformBuffer();
|
UpdateUniformBuffer();
|
||||||
|
|
||||||
vertexBuffer->Bind(commandBuffer->GetHandle());
|
vertexBuffer->Bind(*commandBuffer);
|
||||||
indexBuffer->Bind(commandBuffer->GetHandle());
|
indexBuffer->Bind(*commandBuffer);
|
||||||
|
|
||||||
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
|
graphicsPipeline->SetDescriptorSet(0, *descriptorSet);
|
||||||
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
|
graphicsPipeline->BindDescriptorSets(commandBuffer->GetHandle());
|
||||||
|
|
||||||
indexBuffer->Draw(commandBuffer->GetHandle());
|
indexBuffer->Draw(*commandBuffer);
|
||||||
|
framebuffer->Unbind(*commandBuffer);
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer->GetHandle());
|
instance->GetSwapChain().BeginFrameBuffer(*commandBuffer);
|
||||||
|
|
||||||
|
graphicsPipelinePassthrough->Bind(*commandBuffer);
|
||||||
|
graphicsPipelinePassthrough->SetDescriptorSet(0, *descriptorSetPassthrough);
|
||||||
|
graphicsPipelinePassthrough->BindDescriptorSets(commandBuffer->GetHandle());
|
||||||
|
vertexBufferPassthrough->Bind(*commandBuffer);
|
||||||
|
indexBufferPassthrough->Bind(*commandBuffer);
|
||||||
|
indexBufferPassthrough->Draw(*commandBuffer);
|
||||||
|
|
||||||
|
instance->GetSwapChain().EndFrameBuffer(*commandBuffer);
|
||||||
commandBuffer->End();
|
commandBuffer->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,24 +233,15 @@ private:
|
|||||||
|
|
||||||
shaderUniformBuffer->Update(shaderUniform);
|
shaderUniformBuffer->Update(shaderUniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkShaderModule InitializeShaderModule(const std::vector<char>& code)
|
|
||||||
{
|
|
||||||
VkShaderModuleCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
||||||
createInfo.codeSize = code.size();
|
|
||||||
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
|
|
||||||
|
|
||||||
VkShaderModule shaderModule;
|
|
||||||
CP_VK_ASSERT(vkCreateShaderModule(instance->GetDevice(), &createInfo, nullptr, &shaderModule), "Failed to initialize shader module");
|
|
||||||
|
|
||||||
return shaderModule;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void func(const int* ptr) {
|
||||||
|
*const_cast<int*>(ptr) = 20;
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
CP_ASSERT(glfwInit() == GLFW_TRUE, "Failed to initialize the glfw context");
|
CP_ASSERT(glfwInit() == GLFW_TRUE, "main : Failed to initialize the glfw context");
|
||||||
{
|
{
|
||||||
Application application;
|
Application application;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
|||||||
Reference in New Issue
Block a user