Skip to content

Commit

Permalink
dynamic rendering again :)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtuncbilek95 committed Nov 10, 2024
1 parent 75d5bcf commit 1eb3cf2
Show file tree
Hide file tree
Showing 28 changed files with 1,212 additions and 56 deletions.
71 changes: 59 additions & 12 deletions Example/01-General/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#include <Engine/Vulkan/RHI/Device/VDevice.h>
#include <Engine/Vulkan/RHI/Queue/VQueue.h>
#include <Engine/Vulkan/RHI/Swapchain/VSwapchain.h>

#include <Engine/Vulkan/RHI/Buffer/VBuffer.h>
#include <Engine/Vulkan/RHI/Command/VCmdPool.h>
#include <Engine/Vulkan/RHI/Command/VCmdBuffer.h>
#include <Engine/Vulkan/RHI/Sync/VFence.h>
#include <Engine/Vulkan/RHI/Sync/VSemaphore.h>

using namespace MAGE;

Expand Down Expand Up @@ -46,27 +48,72 @@ int main()
Owned<VQueue> cQueue = device->CreateQueue(vk::QueueFlagBits::eCompute);
Owned<VQueue> tQueue = device->CreateQueue(vk::QueueFlagBits::eTransfer);

Owned<VSwapchain> swapchain = MakeOwned<VSwapchain>(SwapchainProps(vk::Format::eR8G8B8A8Unorm,
Owned<VSwapchain> swapchain = MakeOwned<VSwapchain>(SwapchainProps(vk::Format::eR8G8B8A8Unorm,
vk::PresentModeKHR::eFifoRelaxed, { 1280, 720 }, 2, &*gQueue), &*device);

BufferProps bufferTestProp = BufferProps();
bufferTestProp.memory = device->GetAllocator()->GetAvailableMemory(AllocProps(bufferTestProp.sizeInBytes, vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible));
Owned<VBuffer> bufferTest1 = MakeOwned<VBuffer>(bufferTestProp, &*device);
bufferTest1->Update({ square.data(), square.size() * sizeof(Vertex) });
CmdPoolProps gPoolProps =
{
.queue = &*gQueue,
.createFlags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer
};
Owned<VCmdPool> gPool = MakeOwned<VCmdPool>(gPoolProps, &*device);
Owned<VCmdBuffer> gPrimBuffer = gPool->CreateBuffer();

bufferTestProp.memory = device->GetAllocator()->GetAvailableMemory(AllocProps(bufferTestProp.sizeInBytes, vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible));
Owned<VBuffer> bufferTest2 = MakeOwned<VBuffer>(bufferTestProp, &*device);
bufferTest2->Update({ square.data(), square.size() * sizeof(Vertex) });
Owned<VFence> imgFence = MakeOwned<VFence>(&*device);
Owned<VSemaphore> presentSem = MakeOwned<VSemaphore>(&*device);

window.Show();
while (!window.IsClosed())
{
window.PollEvents();

u32 imgIndex = swapchain->AcquireNextImage(nullptr, &*imgFence);
imgFence->Wait();
imgFence->Reset();

gPrimBuffer->BeginRecord(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);

// Barrier swapchain
ImageBarrierProps barrier = {};
barrier.srcPipeline = vk::PipelineStageFlagBits::eColorAttachmentOutput;
barrier.dstPipeline = vk::PipelineStageFlagBits::eColorAttachmentOutput;
barrier.srcAccessMask = {};
barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
barrier.oldLayout = vk::ImageLayout::ePresentSrcKHR;
barrier.newLayout = vk::ImageLayout::eColorAttachmentOptimal;
barrier.image = swapchain->GetSwapchainImage();

gPrimBuffer->ImageBarrier(barrier);

RenderProps renderProp = {};
renderProp.colorAttachment = { {swapchain->GetSwapchainView(), vk::ImageLayout::eColorAttachmentOptimal, vk::AttachmentLoadOp::eClear,
vk::AttachmentStoreOp::eStore, vk::ClearColorValue(.39f, .58f, .92f, 1.f), vk::ClearDepthStencilValue(1.f, 0)} };
renderProp.extent = swapchain->GetImageSize();
renderProp.layerCount = 1;
renderProp.viewMask = 0;
renderProp.renderFlags = vk::RenderingFlagBits::eContentsSecondaryCommandBuffers;
gPrimBuffer->BeginRendering(renderProp);
gPrimBuffer->EndRendering();

// Barrier again
barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
barrier.oldLayout = vk::ImageLayout::eColorAttachmentOptimal;
barrier.newLayout = vk::ImageLayout::ePresentSrcKHR;
gPrimBuffer->ImageBarrier(barrier);
gPrimBuffer->EndRecord();

gQueue->Submit({ &*gPrimBuffer }, { &*presentSem }, {}, { vk::PipelineStageFlagBits::eColorAttachmentOutput }, nullptr);
swapchain->Present({ &*presentSem });
}
window.Hide();

bufferTest2->Destroy();
bufferTest1->Destroy();
device->WaitForIdle();

imgFence->Destroy();
presentSem->Destroy();
gPrimBuffer->Destroy();
gPool->Destroy();
swapchain->Destroy();
device->Destroy();
instance->Destroy();
Expand Down
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,23 @@
![example event parameter](https://github.com/mtuncbilek95/MAGE/actions/workflows/windows-build.yml/badge.svg)
# M.A.G.E

## NOTES ON PROJECT
- Project continuously gets rework on Graphics Implementation. Because I'm trying new things. If you want results please check older commits.
- Current version is using vulkan.hpp
- I can change anything at anytime. Which means I can always start working from scratch on master. So I don't care what you think. I'm trying to learn.
- Tried descriptor buffers. And its gonna take a long time to find a good implementation for it on general usage.
- I have my own memory allocator design. It has issues but mostly its working fine with a little bit over allocation. But I will try to fix those on packaging since editor side has quite unexpected behaviours.

Modern & Advanced Graphics Engine
## GOOD TO KNOW WHILE WORKING

- The Engine is written in C++20 and uses Vulkan API `v1.3.290.0` for rendering (Will support DX12 in future).
- Current version is using vulkan.hpp
- I have my own memory allocator design. It has issues but mostly its working fine with a little bit over allocation.
- The Engine is still in development and not ready for production.
- While running build generator for cmake, you will see a part where the cmake shows the excluded files. When working with Linux the excluded files needs to belong Win32API and
vice versa. This has been added to CMake with the aim of reducing macro controllers and boosting the compilation speed. **Edit:** It is still there but it's not that important anymore.
Because I literally deep dived into not having layers on platform specific implementations. Couple things are still there for this excluding purpose but most of them are gone.

## IMPLEMENTED FEATURES
- [x] Unit Test Environment (Catch2)
- [x] Win32 Platform
- [ ] Linux Platform
- [x] Vulkan Implementation
- [ ] Job System for multi-thread behaviour
- [x] Job System for multi-thread behaviour
- [x] Runtime Shader Compiler
- [x] Custom Memory Allocator
- [ ] JSON Serialization
- [ ] Encryption
- [ ] Resource Control Mechanism
- [ ] Entity Component System
- [ ] Editor Integration with ImGui
Expand Down Expand Up @@ -61,10 +52,18 @@ Because I literally deep dived into not having layers on platform specific imple
- [ ] DX12 (Graphics SDK)
- [ ] Nvidia Physx (Physics SDK)


## ACTIVE VULKAN FEATURES
- [x] Dynamic Rendering
- [x] RenderPass & FrameBuffer
- [x] Descriptor Buffer
- [x] Descriptor Set
- [x] Bindless Shaders

## THE AIM OF THE SYSTEM
- Windows should work with DX12 no matter what. But for now I don't want the burnout with DX12, so VulkanSDK continues. If I could go the past, I would choose DX12 though.
- I believe the only reason for DX12 would be Xbox support. I will continue my journey with Vulkan as much as possible.
- Linux has no option other than VulkanSDK.
- I already made cross platform support for both Linux and Windows. It's not that hard to make it. The hard part is to make them work together while doing lots of feature
- I already made cross platform support for both Linux and Windows a time ago. It's not that hard to make it. The hard part is to make them work together while doing lots of feature
implementations. So till I get the satisfaction on Win32, I won't touch the Linux part. The system already has the capability to run on Linux.
- Main optimization workflow mostly will be on Windows since buying PS5 Dev Kit is not easy.
- Current goal is not to create showreels but creating crash-less environment
Expand Down
103 changes: 103 additions & 0 deletions Source/Engine/Vulkan/Core/VkUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include "VkUtils.h"

#include <magic_enum.hpp>

namespace MAGE
{
HashMap<vk::Format, u32> MakeFormatSizeMap()
{
HashMap<vk::Format, u32> map;
for (auto format : magic_enum::enum_values<vk::Format>())
{
u32 size = 0;
if (format == vk::Format::eR4G4UnormPack8 || format == vk::Format::eS8Uint) size = 1;
else if (format >= vk::Format::eR4G4B4A4UnormPack16 && format <= vk::Format::eA1R5G5B5UnormPack16)
size = 2;
else if (format >= vk::Format::eR8Unorm && format <= vk::Format::eR8Srgb) size = 1;
else if (format >= vk::Format::eR8G8Unorm && format <= vk::Format::eR8G8Srgb) size = 2;
else if (format >= vk::Format::eR8G8B8Unorm && format <= vk::Format::eB8G8R8Srgb) size = 3;
else if (format >= vk::Format::eR8G8B8A8Unorm && format <= vk::Format::eA2B10G10R10SintPack32)
size = 4;
else if (format >= vk::Format::eR16Unorm && format <= vk::Format::eR16Sfloat) size = 2;
else if (format >= vk::Format::eR16G16Unorm && format <= vk::Format::eR16G16Sfloat) size = 4;
else if (format >= vk::Format::eR16G16B16Unorm && format <= vk::Format::eR16G16B16Sfloat) size = 6;
else if (format >= vk::Format::eR16G16B16A16Unorm && format <= vk::Format::eR16G16B16A16Sfloat)
size = 8;
else if (format >= vk::Format::eR32Uint && format <= vk::Format::eR32Sfloat) size = 4;
else if (format >= vk::Format::eR32G32Uint && format <= vk::Format::eR32G32Sfloat) size = 8;
else if (format >= vk::Format::eR32G32B32Uint && format <= vk::Format::eR32G32B32Sfloat) size = 12;
else if (format >= vk::Format::eR32G32B32A32Uint && format <= vk::Format::eR32G32B32A32Sfloat)
size = 16;
else if (format >= vk::Format::eR64Uint && format <= vk::Format::eR64Sfloat) size = 8;
else if (format >= vk::Format::eR64G64Uint && format <= vk::Format::eR64G64Sfloat) size = 16;
else if (format >= vk::Format::eR64G64B64Uint && format <= vk::Format::eR64G64B64Sfloat) size = 24;
else if (format >= vk::Format::eR64G64B64A64Uint && format <= vk::Format::eR64G64B64A64Sfloat)
size = 32;
else if (format == vk::Format::eB10G11R11UfloatPack32 || format == vk::Format::eE5B9G9R9UfloatPack32
|| format == vk::Format::eX8D24UnormPack32 || format == vk::Format::eD32Sfloat
|| format == vk::Format::eD24UnormS8Uint)
size = 4;
else if (format == vk::Format::eD16Unorm) size = 2;
else if (format == vk::Format::eD16UnormS8Uint) size = 3;
else if (format == vk::Format::eD32SfloatS8Uint) size = 5;
else if (format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock
|| format == vk::Format::eBc1RgbaUnormBlock || format == vk::Format::eBc1RgbaSrgbBlock
|| format == vk::Format::eBc4SnormBlock || format == vk::Format::eBc4UnormBlock)
size = 8;
else if (format == vk::Format::eBc2SrgbBlock || format == vk::Format::eBc2UnormBlock
|| format == vk::Format::eBc3SrgbBlock || format == vk::Format::eBc3UnormBlock
|| format == vk::Format::eBc5SnormBlock || format == vk::Format::eBc5UnormBlock
|| format == vk::Format::eBc6HSfloatBlock || format == vk::Format::eBc6HUfloatBlock
|| format == vk::Format::eBc7SrgbBlock || format == vk::Format::eBc7UnormBlock)
size = 16;
else if (format == vk::Format::eEtc2R8G8B8UnormBlock || format == vk::Format::eEtc2R8G8B8SrgbBlock
|| format == vk::Format::eEtc2R8G8B8A1UnormBlock
|| format == vk::Format::eEtc2R8G8B8A1SrgbBlock
|| format == vk::Format::eEtc2R8G8B8A8UnormBlock
|| format == vk::Format::eEtc2R8G8B8A8SrgbBlock || format == vk::Format::eEacR11UnormBlock
|| format == vk::Format::eEacR11SnormBlock || format == vk::Format::eEacR11G11UnormBlock
|| format == vk::Format::eEacR11G11SnormBlock)
size = 16;
else if (format == vk::Format::eAstc4x4UnormBlock || format == vk::Format::eAstc4x4SfloatBlock
|| format == vk::Format::eAstc4x4SrgbBlock || format == vk::Format::eAstc5x4UnormBlock
|| format == vk::Format::eAstc5x4SfloatBlock || format == vk::Format::eAstc5x4SrgbBlock
|| format == vk::Format::eAstc5x5UnormBlock || format == vk::Format::eAstc5x5SfloatBlock
|| format == vk::Format::eAstc5x5SrgbBlock || format == vk::Format::eAstc6x5UnormBlock
|| format == vk::Format::eAstc6x5SfloatBlock || format == vk::Format::eAstc6x5SrgbBlock
|| format == vk::Format::eAstc6x6UnormBlock || format == vk::Format::eAstc6x6SfloatBlock
|| format == vk::Format::eAstc6x6SrgbBlock || format == vk::Format::eAstc8x5UnormBlock
|| format == vk::Format::eAstc8x5SfloatBlock || format == vk::Format::eAstc8x5SrgbBlock
|| format == vk::Format::eAstc8x6UnormBlock || format == vk::Format::eAstc8x6SfloatBlock
|| format == vk::Format::eAstc8x6SrgbBlock || format == vk::Format::eAstc8x8UnormBlock
|| format == vk::Format::eAstc8x8SfloatBlock || format == vk::Format::eAstc8x8SrgbBlock
|| format == vk::Format::eAstc10x5UnormBlock || format == vk::Format::eAstc10x5SfloatBlock
|| format == vk::Format::eAstc10x5SrgbBlock || format == vk::Format::eAstc10x6UnormBlock
|| format == vk::Format::eAstc10x6SfloatBlock || format == vk::Format::eAstc10x6SrgbBlock
|| format == vk::Format::eAstc10x8UnormBlock || format == vk::Format::eAstc10x8SfloatBlock
|| format == vk::Format::eAstc10x8SrgbBlock || format == vk::Format::eAstc10x10UnormBlock
|| format == vk::Format::eAstc10x10SfloatBlock || format == vk::Format::eAstc10x10SrgbBlock
|| format == vk::Format::eAstc12x10UnormBlock
|| format == vk::Format::eAstc12x10SfloatBlock || format == vk::Format::eAstc12x10SrgbBlock
|| format == vk::Format::eAstc12x12UnormBlock
|| format == vk::Format::eAstc12x12SfloatBlock || format == vk::Format::eAstc12x12SrgbBlock)
size = 16;

map[format] = size;
}

return map;
}

const HashMap<vk::Format, u32> FORMAT_SIZE_MAP = MakeFormatSizeMap();

u32 VkUtils::GetVkTextureSize(vk::Format format)
{
auto size = FORMAT_SIZE_MAP.find(format);
if (size == FORMAT_SIZE_MAP.end() || size->second == 0) [[unlikely]]
{
spdlog::critical("VkFormat not found in the map: {}", magic_enum::enum_name(format));
exit(-1);
}
return size->second;
}
}
20 changes: 20 additions & 0 deletions Source/Engine/Vulkan/Core/VkUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2024 Metehan Tuncbilek
*/

#pragma once

#include "Engine/Core/Core.h"
#include <vulkan/vulkan.hpp>

namespace MAGE
{
namespace VkUtils
{
u32 GetVkTextureSize(vk::Format format);
}
}
38 changes: 25 additions & 13 deletions Source/Engine/Vulkan/RHI/Buffer/VBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,13 @@

namespace MAGE
{
VBuffer::VBuffer(const BufferProps& desc, VDevice* device) : VkObject(device), m_props(desc)
VBuffer::VBuffer(const BufferProps& desc, VDevice* device) : VkObject(device), m_props(desc), m_memoryOffset(0), m_memory(nullptr)
{
vk::BufferCreateInfo bufferInfo = vk::BufferCreateInfo();
bufferInfo.size = desc.sizeInBytes;
bufferInfo.usage = vk::BufferUsageFlagBits::eShaderDeviceAddress | desc.usageFlags;

ErrorUtils::VkAssert(m_rootDevice->GetVkDevice().createBuffer(&bufferInfo, nullptr, &m_buffer), "VBuffer");

vk::MemoryRequirements memReq = vk::MemoryRequirements();
m_rootDevice->GetVkDevice().getBufferMemoryRequirements(m_buffer, &memReq);

u64 offset = desc.memory->Allocate(memReq.size + memReq.alignment);
m_memoryOffset = offset + (offset % memReq.alignment == 0 ? 0 : (memReq.alignment - (offset % memReq.alignment)));

m_rootDevice->GetVkDevice().bindBufferMemory(m_buffer, m_props.memory->m_memory, m_memoryOffset);
}

VBuffer::~VBuffer()
Expand All @@ -32,13 +24,33 @@ namespace MAGE
{
vk::BufferDeviceAddressInfo addressInfo = {};
addressInfo.buffer = m_buffer;
m_props.memory->m_address = m_rootDevice->GetVkDevice().getBufferAddress(&addressInfo);
return m_props.memory->m_address;
m_memory->m_address = m_rootDevice->GetVkDevice().getBufferAddress(&addressInfo);
return m_memory->m_address;
}

usize VBuffer::GetRequestedSize() const
{
vk::MemoryRequirements memReq = vk::MemoryRequirements();
m_rootDevice->GetVkDevice().getBufferMemoryRequirements(m_buffer, &memReq);
return memReq.size + memReq.alignment;
}

void VBuffer::BindMemory(VMemory* memory)
{
vk::MemoryRequirements memReq = vk::MemoryRequirements();
m_rootDevice->GetVkDevice().getBufferMemoryRequirements(m_buffer, &memReq);

u64 offset = memory->Allocate(memReq.size + memReq.alignment);
m_memoryOffset = offset + (offset % memReq.alignment == 0 ? 0 : (memReq.alignment - (offset % memReq.alignment)));

m_rootDevice->GetVkDevice().bindBufferMemory(m_buffer, memory->m_memory, m_memoryOffset);

m_memory = memory;
}

void VBuffer::Update(RawBuffer buffer) const
{
memcpy(m_props.memory->m_mappedData + m_memoryOffset, buffer.Data(), buffer.Size());
memcpy(m_memory->m_mappedData + m_memoryOffset, buffer.Data(), buffer.Size());
}

void VBuffer::Destroy()
Expand All @@ -48,7 +60,7 @@ namespace MAGE
m_rootDevice->GetVkDevice().destroyBuffer(m_buffer);
m_buffer = VK_NULL_HANDLE;

m_props.memory->Free(0, m_memoryOffset);
m_memory->Free(0, m_memoryOffset);
}
}
}
12 changes: 6 additions & 6 deletions Source/Engine/Vulkan/RHI/Buffer/VBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ namespace MAGE
struct BufferProps final
{
BufferProps(usize size = 0,
vk::BufferUsageFlags flag = {},
VMemory* mem = nullptr) : sizeInBytes(size), usageFlags(flag), memory(mem)
vk::BufferUsageFlags flag = {}) : sizeInBytes(size), usageFlags(flag)
{}

usize sizeInBytes;
vk::BufferUsageFlags usageFlags;
VMemory* memory;
};

class VBuffer final : public VkObject
Expand All @@ -36,22 +34,24 @@ namespace MAGE
~VBuffer() override final;

inline vk::Buffer GetVkBuffer() const { return m_buffer; }
inline vk::DeviceMemory GetVkMemory() const { return m_props.memory->m_memory; }
inline vk::DeviceMemory GetVkMemory() const { return m_memory->m_memory; }
inline vk::BufferUsageFlags GetVkUsage() const { return m_props.usageFlags; }

vk::DeviceAddress GetVkAddress() const;

inline usize GetMemoryOffset() const { return m_memoryOffset; }
inline usize GetTotalSize() const { return m_props.sizeInBytes; }
inline u8* GetMappedData() const { return m_memory->m_mappedData; }

inline u8* GetMappedData() const { return m_props.memory->m_mappedData; }
usize GetRequestedSize() const;

void BindMemory(VMemory* memory);
void Update(RawBuffer buffer) const;

void Destroy() override final;

private:
BufferProps m_props;
VMemory* m_memory;

vk::Buffer m_buffer;
usize m_memoryOffset;
Expand Down
Loading

0 comments on commit 1eb3cf2

Please sign in to comment.