608 lines
24 KiB
C++
608 lines
24 KiB
C++
// =============================================
|
|
// Aster: model_render.cpp
|
|
// Copyright (c) 2020-2024 Anish Bhobe
|
|
// =============================================
|
|
|
|
#include "buffer.h"
|
|
#include "constants.h"
|
|
#include "context.h"
|
|
#include "device.h"
|
|
#include "global.h"
|
|
#include "image.h"
|
|
#include "physical_device.h"
|
|
#include "pipeline.h"
|
|
#include "swapchain.h"
|
|
#include "window.h"
|
|
|
|
#include "frame.h"
|
|
#include "helpers.h"
|
|
|
|
#include "model_loader.h"
|
|
#include "pipeline_utils.h"
|
|
#include "render_resource_manager.h"
|
|
|
|
#include <EASTL/array.h>
|
|
#include <stb_image.h>
|
|
#include <tiny_gltf.h>
|
|
#include <filesystem>
|
|
|
|
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
|
constexpr auto MODEL_FILE = "model/Box.glb";
|
|
|
|
struct ImageFile
|
|
{
|
|
void *m_Data = nullptr;
|
|
u32 m_Width = 0;
|
|
u32 m_Height = 0;
|
|
u32 m_NumChannels = 0;
|
|
bool m_Constant = false;
|
|
|
|
bool Load(cstr fileName);
|
|
bool Load(vec4 color);
|
|
[[nodiscard]] usize GetSize() const;
|
|
~ImageFile();
|
|
};
|
|
|
|
struct Camera
|
|
{
|
|
mat4 m_Model;
|
|
mat4 m_View;
|
|
mat4 m_Perspective;
|
|
};
|
|
|
|
int
|
|
main(int, char **)
|
|
{
|
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
|
|
|
Context context = {"ModelRender [WIP]", VERSION};
|
|
Window window = {"ModelRender [WIP] (Aster)", &context, {640, 480}};
|
|
|
|
PhysicalDevices physicalDevices = {&window, &context};
|
|
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
|
|
|
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
|
|
|
Features enabledDeviceFeatures = {
|
|
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
|
.m_Vulkan12Features =
|
|
{
|
|
.descriptorIndexing = true,
|
|
.shaderSampledImageArrayNonUniformIndexing = true,
|
|
.shaderStorageBufferArrayNonUniformIndexing = true,
|
|
.shaderStorageImageArrayNonUniformIndexing = true,
|
|
.descriptorBindingUniformBufferUpdateAfterBind = true, // Not related to Bindless
|
|
.descriptorBindingSampledImageUpdateAfterBind = true,
|
|
.descriptorBindingStorageImageUpdateAfterBind = true,
|
|
.descriptorBindingStorageBufferUpdateAfterBind = true,
|
|
.descriptorBindingPartiallyBound = true,
|
|
.runtimeDescriptorArray = true,
|
|
},
|
|
.m_Vulkan13Features = {.dynamicRendering = true},
|
|
};
|
|
|
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
|
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
|
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
|
RenderResourceManager resourceManager(&device, 10);
|
|
|
|
Pipeline pipeline = CreatePipeline(&device, &swapchain, &resourceManager);
|
|
|
|
Camera camera = {
|
|
.m_Model = {1.0f},
|
|
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
|
|
.m_Perspective = glm::perspective(
|
|
70_deg, Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height), 0.1f, 100.0f),
|
|
};
|
|
|
|
vk::DescriptorPool descriptorPool;
|
|
vk::DescriptorSet descriptorSet;
|
|
|
|
{
|
|
vk::DescriptorSetLayout descriptorSetLayout = pipeline.m_SetLayouts[1];
|
|
eastl::array poolSizes = {
|
|
vk::DescriptorPoolSize{
|
|
.type = vk::DescriptorType::eUniformBuffer,
|
|
.descriptorCount = 1,
|
|
},
|
|
vk::DescriptorPoolSize{
|
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
|
.descriptorCount = 1,
|
|
},
|
|
};
|
|
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
|
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
|
AbortIfFailed(device.m_Device.createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
|
|
|
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
|
.descriptorPool = descriptorPool,
|
|
.descriptorSetCount = 1,
|
|
.pSetLayouts = &descriptorSetLayout,
|
|
};
|
|
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet));
|
|
}
|
|
|
|
vk::CommandPool copyPool;
|
|
vk::CommandBuffer copyBuffer;
|
|
|
|
{
|
|
vk::CommandPoolCreateInfo poolCreateInfo = {
|
|
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
|
.queueFamilyIndex = queueAllocation.m_Family,
|
|
};
|
|
AbortIfFailedM(device.m_Device.createCommandPool(&poolCreateInfo, nullptr, ©Pool),
|
|
"Copy command pool creation failed.");
|
|
vk::CommandBufferAllocateInfo bufferAllocateInfo = {
|
|
.commandPool = copyPool,
|
|
.level = vk::CommandBufferLevel::ePrimary,
|
|
.commandBufferCount = 1,
|
|
};
|
|
AbortIfFailedM(device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, ©Buffer),
|
|
"Copy command buffer allocation failed.");
|
|
}
|
|
|
|
eastl::array vertices = {
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
|
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
|
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
|
|
};
|
|
|
|
ImageFile crateImageFile;
|
|
ImageFile plainImageFile;
|
|
assert(crateImageFile.Load("image/container.jpg"));
|
|
INFO("Image {}x{} : {} channels", crateImageFile.m_Width, crateImageFile.m_Height, crateImageFile.m_NumChannels);
|
|
assert(plainImageFile.Load({0.7f, 0.4f, 0.1f, 1.0f}));
|
|
|
|
UniformStorageBuffer pvbo;
|
|
Texture crateTexture;
|
|
Texture plainTexture;
|
|
crateTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false,
|
|
"Crate Texture");
|
|
plainTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false,
|
|
"Plain Texture");
|
|
pvbo.Init(&device, vertices.size() * sizeof vertices[0], "Pull VBO");
|
|
pvbo.Write(&device, 0, pvbo.GetSize(), vertices.data());
|
|
|
|
auto crateTextureId = resourceManager.Commit(&crateTexture);
|
|
auto plainTextureId = resourceManager.Commit(&plainTexture);
|
|
auto pvboBufferId = resourceManager.Commit(&pvbo);
|
|
|
|
{
|
|
StagingBuffer imageStaging1, imageStaging2;
|
|
|
|
imageStaging1.Init(&device, crateImageFile.GetSize(), "Image Staging 1");
|
|
imageStaging1.Write(&device, 0, crateImageFile.GetSize(), crateImageFile.m_Data);
|
|
|
|
imageStaging2.Init(&device, plainImageFile.GetSize(), "Image Staging 2");
|
|
imageStaging2.Write(&device, 0, plainImageFile.GetSize(), plainImageFile.m_Data);
|
|
|
|
eastl::array imageReadyToWrite = {
|
|
vk::ImageMemoryBarrier{
|
|
.oldLayout = vk::ImageLayout::eUndefined,
|
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
|
.image = crateTexture.m_Image,
|
|
.subresourceRange =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
},
|
|
vk::ImageMemoryBarrier{
|
|
.oldLayout = vk::ImageLayout::eUndefined,
|
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
|
.image = plainTexture.m_Image,
|
|
.subresourceRange =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
},
|
|
};
|
|
|
|
eastl::array imageReadyToRead = {
|
|
vk::ImageMemoryBarrier{
|
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
|
.image = crateTexture.m_Image,
|
|
.subresourceRange =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
},
|
|
vk::ImageMemoryBarrier{
|
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
|
.image = plainTexture.m_Image,
|
|
.subresourceRange =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
},
|
|
};
|
|
|
|
vk::Fence fence;
|
|
vk::FenceCreateInfo fenceCreateInfo = {};
|
|
AbortIfFailed(device.m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
|
|
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
|
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
|
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
|
nullptr, 0, nullptr, Cast<u32>(imageReadyToWrite.size()), imageReadyToWrite.data());
|
|
|
|
vk::BufferImageCopy imageCopy = {
|
|
.bufferOffset = 0,
|
|
.bufferRowLength = crateImageFile.m_Width,
|
|
.bufferImageHeight = crateImageFile.m_Height,
|
|
.imageSubresource =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.mipLevel = 0,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
.imageOffset = {},
|
|
.imageExtent = {crateImageFile.m_Width, crateImageFile.m_Height, 1},
|
|
};
|
|
copyBuffer.copyBufferToImage(imageStaging1.m_Buffer, crateTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
|
|
1, &imageCopy);
|
|
copyBuffer.copyBufferToImage(imageStaging2.m_Buffer, plainTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
|
|
1, &imageCopy);
|
|
|
|
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
|
0, nullptr, 0, nullptr, Cast<u32>(imageReadyToRead.size()), imageReadyToRead.data());
|
|
|
|
AbortIfFailed(copyBuffer.end());
|
|
|
|
vk::SubmitInfo submitInfo = {
|
|
.commandBufferCount = 1,
|
|
.pCommandBuffers = ©Buffer,
|
|
};
|
|
|
|
AbortIfFailed(commandQueue.submit(1, &submitInfo, fence));
|
|
INFO("Submit copy");
|
|
|
|
AbortIfFailed(device.m_Device.waitForFences(1, &fence, true, MaxValue<u64>));
|
|
INFO("Fence wait");
|
|
|
|
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
|
|
|
device.m_Device.destroy(fence, nullptr);
|
|
imageStaging1.Destroy(&device);
|
|
imageStaging2.Destroy(&device);
|
|
}
|
|
|
|
UniformBuffer ubo;
|
|
ubo.Init(&device, sizeof camera, "Camera UBO");
|
|
ubo.Write(&device, 0, sizeof camera, &camera);
|
|
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
|
.buffer = ubo.m_Buffer,
|
|
.offset = 0,
|
|
.range = ubo.GetSize(),
|
|
};
|
|
eastl::array writeDescriptors = {
|
|
vk::WriteDescriptorSet{
|
|
.dstSet = descriptorSet,
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
|
.pBufferInfo = &descriptorBufferInfo,
|
|
},
|
|
};
|
|
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
|
|
|
resourceManager.Update();
|
|
|
|
// Persistent variables
|
|
vk::Viewport viewport = {
|
|
.x = 0,
|
|
.y = Cast<f32>(swapchain.m_Extent.height),
|
|
.width = Cast<f32>(swapchain.m_Extent.width),
|
|
.height = -Cast<f32>(swapchain.m_Extent.height),
|
|
.minDepth = 0.0,
|
|
.maxDepth = 1.0,
|
|
};
|
|
|
|
vk::Rect2D scissor = {
|
|
.offset = {0, 0},
|
|
.extent = swapchain.m_Extent,
|
|
};
|
|
|
|
auto fnResizeViewportScissor = [&viewport, &scissor](vk::Extent2D extent) {
|
|
viewport.y = Cast<f32>(extent.height);
|
|
viewport.width = Cast<f32>(extent.width);
|
|
viewport.height = -Cast<f32>(extent.height);
|
|
scissor.extent = extent;
|
|
};
|
|
swapchain.RegisterResizeCallback(fnResizeViewportScissor);
|
|
|
|
vk::ImageSubresourceRange subresourceRange = {
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
};
|
|
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
|
.oldLayout = vk::ImageLayout::eUndefined,
|
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
|
|
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
|
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
|
|
{
|
|
u32 depthImageIdx = 0;
|
|
for (auto &depthImage : depthImages)
|
|
{
|
|
auto name = fmt::format("Depth {}", depthImageIdx++);
|
|
depthImage.Init(&device, swapchain.m_Extent, name.c_str());
|
|
}
|
|
}
|
|
|
|
auto fnRecreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) {
|
|
u32 depthImageIdx = 0;
|
|
for (auto &depthImage : depthImages)
|
|
{
|
|
auto name = fmt::format("Depth {}", depthImageIdx++);
|
|
depthImage.Destroy(&device);
|
|
depthImage.Init(&device, extent, name.c_str());
|
|
}
|
|
};
|
|
swapchain.RegisterResizeCallback(fnRecreateDepthBuffers);
|
|
|
|
Time::Init();
|
|
|
|
Handle *pushData = &crateTextureId;
|
|
Handle *otherPushData = &plainTextureId;
|
|
|
|
bool prevPressed = false;
|
|
auto isSpaceJustPressed = [&prevPressed, &window] {
|
|
const bool pressed = glfwGetKey(window.m_Window, GLFW_KEY_SPACE) == GLFW_PRESS;
|
|
const bool justPressed = pressed & !prevPressed;
|
|
prevPressed = pressed;
|
|
return justPressed;
|
|
};
|
|
|
|
INFO("Starting loop");
|
|
while (window.Poll())
|
|
{
|
|
Time::Update();
|
|
|
|
if (isSpaceJustPressed())
|
|
{
|
|
eastl::swap(pushData, otherPushData);
|
|
}
|
|
|
|
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
|
ubo.Write(&device, 0, sizeof camera, &camera);
|
|
|
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
|
|
|
u32 imageIndex = currentFrame->m_ImageIdx;
|
|
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
|
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
|
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
|
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View;
|
|
|
|
topOfThePipeBarrier.image = currentImage;
|
|
renderToPresentBarrier.image = currentImage;
|
|
|
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
|
AbortIfFailed(cmd.begin(&beginInfo));
|
|
|
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
|
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
|
|
|
// Render
|
|
eastl::array attachmentInfos = {
|
|
vk::RenderingAttachmentInfo{
|
|
.imageView = currentImageView,
|
|
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
|
},
|
|
};
|
|
|
|
vk::RenderingAttachmentInfo depthAttachment = {
|
|
.imageView = currentDepthImageView,
|
|
.imageLayout = vk::ImageLayout::eDepthAttachmentOptimal,
|
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
|
.storeOp = vk::AttachmentStoreOp::eDontCare,
|
|
.clearValue = vk::ClearDepthStencilValue{.depth = 1.0f, .stencil = 0},
|
|
};
|
|
|
|
vk::RenderingInfo renderingInfo = {
|
|
.renderArea = {.extent = swapchain.m_Extent},
|
|
.layerCount = 1,
|
|
.colorAttachmentCount = Cast<u32>(attachmentInfos.size()),
|
|
.pColorAttachments = attachmentInfos.data(),
|
|
.pDepthAttachment = &depthAttachment,
|
|
};
|
|
|
|
cmd.beginRendering(&renderingInfo);
|
|
|
|
cmd.setViewport(0, 1, &viewport);
|
|
cmd.setScissor(0, 1, &scissor);
|
|
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof *pushData, pushData);
|
|
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof *pushData, sizeof pvboBufferId,
|
|
&pvboBufferId);
|
|
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
|
&resourceManager.m_DescriptorSet, 0, nullptr);
|
|
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr);
|
|
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
|
|
|
cmd.endRendering();
|
|
|
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
|
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
|
|
|
AbortIfFailed(cmd.end());
|
|
|
|
vk::PipelineStageFlags waitDstStage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
|
vk::SubmitInfo submitInfo = {
|
|
.waitSemaphoreCount = 1,
|
|
.pWaitSemaphores = ¤tFrame->m_ImageAcquireSem,
|
|
.pWaitDstStageMask = &waitDstStage,
|
|
.commandBufferCount = 1,
|
|
.pCommandBuffers = &cmd,
|
|
.signalSemaphoreCount = 1,
|
|
.pSignalSemaphores = ¤tFrame->m_RenderFinishSem,
|
|
};
|
|
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
|
|
|
currentFrame->Present(commandQueue, &swapchain, &window);
|
|
}
|
|
|
|
AbortIfFailed(device.m_Device.waitIdle());
|
|
|
|
for (auto &depthImage : depthImages)
|
|
{
|
|
depthImage.Destroy(&device);
|
|
}
|
|
ubo.Destroy(&device);
|
|
device.m_Device.destroy(descriptorPool, nullptr);
|
|
device.m_Device.destroy(copyPool, nullptr);
|
|
crateTexture.Destroy(&device);
|
|
plainTexture.Destroy(&device);
|
|
pvbo.Destroy(&device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
ImageFile::Load(vec4 color)
|
|
{
|
|
constexpr usize size = 512llu * 512llu * 4llu;
|
|
u8 *pData = new u8[size];
|
|
|
|
const vec4 color255 = 255.999f * color;
|
|
const glm::vec<4, u8> color8 = color255;
|
|
|
|
for (usize i = 0; i < size; i += 4)
|
|
{
|
|
memcpy(pData + i, &color8, sizeof color8);
|
|
}
|
|
|
|
m_Data = pData;
|
|
m_Constant = true;
|
|
m_Height = 512;
|
|
m_Width = 512;
|
|
m_NumChannels = 4;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ImageFile::Load(cstr fileName)
|
|
{
|
|
int width, height, nrChannels;
|
|
m_Data = stbi_load(fileName, &width, &height, &nrChannels, 4);
|
|
ERROR_IF(!m_Data, "Could not load {}", fileName);
|
|
|
|
if (!m_Data)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_Width = width;
|
|
m_Height = height;
|
|
m_NumChannels = 4;
|
|
m_Constant = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
usize
|
|
ImageFile::GetSize() const
|
|
{
|
|
return Cast<usize>(m_Width) * m_Height * m_NumChannels;
|
|
}
|
|
|
|
ImageFile::~ImageFile()
|
|
{
|
|
if (m_Constant)
|
|
{
|
|
delete[] Cast<u8 *>(m_Data);
|
|
}
|
|
else
|
|
{
|
|
stbi_image_free(m_Data);
|
|
}
|
|
m_Data = nullptr;
|
|
}
|