Setup for bindless.
This commit is contained in:
parent
fa8351c866
commit
c7ea45bce7
|
|
@ -420,13 +420,13 @@ main(int, char **)
|
||||||
.extent = swapchain.m_Extent,
|
.extent = swapchain.m_Extent,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ResizeViewportScissor = [&viewport, &scissor](vk::Extent2D extent) {
|
auto resizeViewportScissor = [&viewport, &scissor](vk::Extent2D extent) {
|
||||||
viewport.y = Cast<f32>(extent.height);
|
viewport.y = Cast<f32>(extent.height);
|
||||||
viewport.width = Cast<f32>(extent.width);
|
viewport.width = Cast<f32>(extent.width);
|
||||||
viewport.height = -Cast<f32>(extent.height);
|
viewport.height = -Cast<f32>(extent.height);
|
||||||
scissor.extent = extent;
|
scissor.extent = extent;
|
||||||
};
|
};
|
||||||
swapchain.RegisterResizeCallback(ResizeViewportScissor);
|
swapchain.RegisterResizeCallback(resizeViewportScissor);
|
||||||
|
|
||||||
vk::ImageSubresourceRange subresourceRange = {
|
vk::ImageSubresourceRange subresourceRange = {
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -479,7 +479,7 @@ main(int, char **)
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto RecreateDepthBuffers = [&device, &depthImages, &depthViews, depthSubresourceRange](vk::Extent2D extent) {
|
auto recreateDepthBuffers = [&device, &depthImages, &depthViews, depthSubresourceRange](vk::Extent2D extent) {
|
||||||
for (auto &depthView : depthViews)
|
for (auto &depthView : depthViews)
|
||||||
{
|
{
|
||||||
device.m_Device.destroy(depthView, nullptr);
|
device.m_Device.destroy(depthView, nullptr);
|
||||||
|
|
@ -500,7 +500,7 @@ main(int, char **)
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
swapchain.RegisterResizeCallback(RecreateDepthBuffers);
|
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
||||||
|
|
||||||
Time::Init();
|
Time::Init();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# CMakeList.txt ; CMake project for box
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
||||||
|
find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
||||||
|
|
||||||
|
add_executable(model_render model_render.cpp
|
||||||
|
pipeline_utils.cpp
|
||||||
|
pipeline_utils.h
|
||||||
|
render_resource_manager.cpp
|
||||||
|
render_resource_manager.h)
|
||||||
|
add_shader(model_render shader/model.vert.glsl)
|
||||||
|
add_shader(model_render shader/model.frag.glsl)
|
||||||
|
|
||||||
|
target_link_libraries(model_render PRIVATE aster_core)
|
||||||
|
target_link_libraries(model_render PRIVATE util_helper)
|
||||||
|
|
||||||
|
target_include_directories(model_render PRIVATE ${TINYGLTF_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
add_resource_dir(model_render model)
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,624 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: model_render.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#define TINYGLTF_NOEXCEPTION
|
||||||
|
#define JSON_NOEXCEPTION
|
||||||
|
|
||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#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 "pipeline_utils.h"
|
||||||
|
#include "render_resource_manager.h"
|
||||||
|
|
||||||
|
#include <EASTL/array.h>
|
||||||
|
#include <tiny_gltf.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
|
constexpr auto MODEL_FILE = "model/Box.glb";
|
||||||
|
|
||||||
|
struct ImageFile
|
||||||
|
{
|
||||||
|
u8 *m_Data = nullptr;
|
||||||
|
u32 m_Width = 512;
|
||||||
|
u32 m_Height = 512;
|
||||||
|
u32 m_NumChannels = 4;
|
||||||
|
|
||||||
|
bool Load(vec4 color);
|
||||||
|
[[nodiscard]] usize GetSize() const;
|
||||||
|
~ImageFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Camera
|
||||||
|
{
|
||||||
|
mat4 m_Model;
|
||||||
|
mat4 m_View;
|
||||||
|
mat4 m_Perspective;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto GLTF_ASCII_FILE_EXTENSION = ".gltf";
|
||||||
|
constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb";
|
||||||
|
|
||||||
|
void
|
||||||
|
LoadModel(cstr path)
|
||||||
|
{
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF loader;
|
||||||
|
|
||||||
|
const auto fsPath = fs::absolute(path);
|
||||||
|
const auto ext = fsPath.extension();
|
||||||
|
if (ext.c_str() == GLTF_ASCII_FILE_EXTENSION)
|
||||||
|
{
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
if (loader.LoadASCIIFromFile(&model, &err, &warn, fsPath.generic_string()))
|
||||||
|
{
|
||||||
|
ERROR_IF(!err.empty(), "{}", err)
|
||||||
|
ELSE_IF_WARN(!warn.empty(), "{}", warn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ext.c_str() == GLTF_BINARY_FILE_EXTENSION)
|
||||||
|
{
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
if (loader.LoadBinaryFromFile(&model, &err, &warn, fsPath.generic_string()))
|
||||||
|
{
|
||||||
|
ERROR_IF(!err.empty(), "{}", err)
|
||||||
|
ELSE_IF_WARN(!warn.empty(), "{}", warn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char **)
|
||||||
|
{
|
||||||
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||||
|
|
||||||
|
Context context = {"Box", VERSION};
|
||||||
|
Window window = {"Box (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},
|
||||||
|
.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);
|
||||||
|
|
||||||
|
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_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageFile imageFile;
|
||||||
|
bool loaded = imageFile.Load({0.7f, 0.4f, 0.1f, 1.0f});
|
||||||
|
assert(loaded);
|
||||||
|
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||||
|
|
||||||
|
VertexBuffer vbo;
|
||||||
|
Texture crate;
|
||||||
|
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
||||||
|
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, false, "Crate Texture");
|
||||||
|
|
||||||
|
{
|
||||||
|
StagingBuffer vertexStaging, imageStaging;
|
||||||
|
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
|
||||||
|
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||||
|
|
||||||
|
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
||||||
|
INFO("fine {}", imageFile.GetSize());
|
||||||
|
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier imageReadyToWrite = {
|
||||||
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.image = crate.m_Image,
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier imageReadyToRead = {
|
||||||
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.image = crate.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, 1, &imageReadyToWrite);
|
||||||
|
|
||||||
|
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
|
||||||
|
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
||||||
|
|
||||||
|
vk::BufferImageCopy imageCopy = {
|
||||||
|
.bufferOffset = 0,
|
||||||
|
.bufferRowLength = imageFile.m_Width,
|
||||||
|
.bufferImageHeight = imageFile.m_Height,
|
||||||
|
.imageSubresource =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.mipLevel = 0,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
.imageOffset = {},
|
||||||
|
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1},
|
||||||
|
};
|
||||||
|
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate.m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||||
|
&imageCopy);
|
||||||
|
|
||||||
|
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
||||||
|
0, nullptr, 0, nullptr, 1, &imageReadyToRead);
|
||||||
|
|
||||||
|
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);
|
||||||
|
vertexStaging.Destroy(&device);
|
||||||
|
imageStaging.Destroy(&device);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageView imageView;
|
||||||
|
vk::Sampler sampler;
|
||||||
|
{
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = crate.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = vk::Format::eR8G8B8A8Srgb,
|
||||||
|
.components =
|
||||||
|
vk::ComponentMapping{
|
||||||
|
.r = vk::ComponentSwizzle::eIdentity,
|
||||||
|
.g = vk::ComponentSwizzle::eIdentity,
|
||||||
|
.b = vk::ComponentSwizzle::eIdentity,
|
||||||
|
.a = vk::ComponentSwizzle::eIdentity,
|
||||||
|
},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &imageView));
|
||||||
|
vk::SamplerCreateInfo samplerCreateInfo = {
|
||||||
|
.magFilter = vk::Filter::eLinear,
|
||||||
|
.minFilter = vk::Filter::eLinear,
|
||||||
|
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||||
|
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.mipLodBias = 0.2,
|
||||||
|
.anisotropyEnable = true,
|
||||||
|
.maxAnisotropy = 1.0f,
|
||||||
|
.compareEnable = false,
|
||||||
|
.minLod = 0,
|
||||||
|
.maxLod = 4,
|
||||||
|
.unnormalizedCoordinates = false,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||||
|
.sampler = sampler,
|
||||||
|
.imageView = imageView,
|
||||||
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
|
};
|
||||||
|
eastl::array writeDescriptors = {
|
||||||
|
vk::WriteDescriptorSet{
|
||||||
|
.dstSet = descriptorSet,
|
||||||
|
.dstBinding = 0,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||||
|
.pBufferInfo = &descriptorBufferInfo,
|
||||||
|
},
|
||||||
|
vk::WriteDescriptorSet{
|
||||||
|
.dstSet = descriptorSet,
|
||||||
|
.dstBinding = 1,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.pImageInfo = &descriptorImageInfo,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
eastl::fixed_vector<vk::ImageView, MAX_FRAMES_IN_FLIGHT> depthViews(frameManager.m_FramesInFlight);
|
||||||
|
|
||||||
|
vk::ImageSubresourceRange depthSubresourceRange = {
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
auto name = fmt::format("Depth image {}", index);
|
||||||
|
depthImage.Init(&device, swapchain.m_Extent, name.c_str());
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = depthImage.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = vk::Format::eD32Sfloat,
|
||||||
|
.components = vk::ComponentMapping{.r = vk::ComponentSwizzle::eIdentity},
|
||||||
|
.subresourceRange = depthSubresourceRange,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &depthViews[index]));
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fnRecreateDepthBuffers = [&device, &depthImages, &depthViews, depthSubresourceRange](vk::Extent2D extent) {
|
||||||
|
for (const auto &depthView : depthViews)
|
||||||
|
{
|
||||||
|
device.m_Device.destroy(depthView, nullptr);
|
||||||
|
}
|
||||||
|
u32 index = 0;
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
depthImage.Destroy(&device);
|
||||||
|
depthImage.Init(&device, extent, "Depth");
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = depthImage.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = vk::Format::eD32Sfloat,
|
||||||
|
.components = vk::ComponentMapping{.r = vk::ComponentSwizzle::eIdentity},
|
||||||
|
.subresourceRange = depthSubresourceRange,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &depthViews[index]));
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
swapchain.RegisterResizeCallback(fnRecreateDepthBuffers);
|
||||||
|
|
||||||
|
Time::Init();
|
||||||
|
|
||||||
|
INFO("Starting loop");
|
||||||
|
while (window.Poll())
|
||||||
|
{
|
||||||
|
Time::Update();
|
||||||
|
|
||||||
|
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 = depthViews[currentFrame->m_FrameIdx];
|
||||||
|
|
||||||
|
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.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr);
|
||||||
|
usize offsets = 0;
|
||||||
|
cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets);
|
||||||
|
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 &depthView : depthViews)
|
||||||
|
{
|
||||||
|
device.m_Device.destroy(depthView, nullptr);
|
||||||
|
}
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
depthImage.Destroy(&device);
|
||||||
|
}
|
||||||
|
device.m_Device.destroy(sampler, nullptr);
|
||||||
|
device.m_Device.destroy(imageView, nullptr);
|
||||||
|
ubo.Destroy(&device);
|
||||||
|
device.m_Device.destroy(descriptorPool, nullptr);
|
||||||
|
device.m_Device.destroy(copyPool, nullptr);
|
||||||
|
crate.Destroy(&device);
|
||||||
|
vbo.Destroy(&device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ImageFile::Load(vec4 color)
|
||||||
|
{
|
||||||
|
constexpr usize size = 512llu * 512llu * 4llu;
|
||||||
|
m_Data = new u8[size];
|
||||||
|
|
||||||
|
vec4 color255 = 255.999f * color;
|
||||||
|
glm::vec<4, u8> color8 = color255;
|
||||||
|
|
||||||
|
for (usize i = 0; i < size; i += 4)
|
||||||
|
{
|
||||||
|
memcpy(m_Data + i, &color8, sizeof color8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize
|
||||||
|
ImageFile::GetSize() const
|
||||||
|
{
|
||||||
|
return m_Width * m_Height * m_NumChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageFile::~ImageFile()
|
||||||
|
{
|
||||||
|
delete[] m_Data;
|
||||||
|
m_Data = nullptr;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: pipeline_utils.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "render_resource_manager.h"
|
||||||
|
#include "swapchain.h"
|
||||||
|
|
||||||
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
|
Pipeline
|
||||||
|
CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderResourceManager *resourceManager)
|
||||||
|
{
|
||||||
|
// Pipeline Setup
|
||||||
|
auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE);
|
||||||
|
auto fragmentShaderModule = CreateShader(device, FRAGMENT_SHADER_FILE);
|
||||||
|
|
||||||
|
eastl::array<vk::PipelineShaderStageCreateInfo, 2> shaderStages = {{
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eVertex,
|
||||||
|
.module = vertexShaderModule,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.stage = vk::ShaderStageFlagBits::eFragment,
|
||||||
|
.module = fragmentShaderModule,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
eastl::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
|
||||||
|
|
||||||
|
descriptorSetLayouts.push_back(resourceManager->m_SetLayout);
|
||||||
|
|
||||||
|
{
|
||||||
|
eastl::array descriptorSetLayoutBindings = {
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = 0,
|
||||||
|
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||||
|
},
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||||
|
.bindingCount = Cast<u32>(descriptorSetLayoutBindings.size()),
|
||||||
|
.pBindings = descriptorSetLayoutBindings.data(),
|
||||||
|
};
|
||||||
|
vk::DescriptorSetLayout descriptorSetLayout;
|
||||||
|
AbortIfFailed(
|
||||||
|
device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout));
|
||||||
|
descriptorSetLayouts.push_back(descriptorSetLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
|
.setLayoutCount = Cast<u32>(descriptorSetLayouts.size()),
|
||||||
|
.pSetLayouts = descriptorSetLayouts.data(),
|
||||||
|
.pushConstantRangeCount = 0,
|
||||||
|
.pPushConstantRanges = nullptr,
|
||||||
|
};
|
||||||
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||||
|
device->SetName(pipelineLayout, "Box Layout");
|
||||||
|
|
||||||
|
descriptorSetLayouts[0] = nullptr; // Not owned.
|
||||||
|
|
||||||
|
vk::VertexInputBindingDescription inputBindingDescription = Vertex::GetBinding(0);
|
||||||
|
auto inputAttributeDescription = Vertex::GetAttributes(0);
|
||||||
|
|
||||||
|
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
|
||||||
|
.vertexBindingDescriptionCount = 1,
|
||||||
|
.pVertexBindingDescriptions = &inputBindingDescription,
|
||||||
|
.vertexAttributeDescriptionCount = Cast<u32>(inputAttributeDescription.size()),
|
||||||
|
.pVertexAttributeDescriptions = inputAttributeDescription.data(),
|
||||||
|
};
|
||||||
|
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||||
|
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||||
|
.primitiveRestartEnable = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = {
|
||||||
|
.viewportCount = 1,
|
||||||
|
.scissorCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
|
||||||
|
.depthClampEnable = false,
|
||||||
|
.rasterizerDiscardEnable = false,
|
||||||
|
.polygonMode = vk::PolygonMode::eFill,
|
||||||
|
.cullMode = vk::CullModeFlagBits::eNone,
|
||||||
|
.frontFace = vk::FrontFace::eCounterClockwise,
|
||||||
|
.depthBiasEnable = false,
|
||||||
|
.lineWidth = 1.0,
|
||||||
|
};
|
||||||
|
vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
|
||||||
|
.rasterizationSamples = vk::SampleCountFlagBits::e1,
|
||||||
|
.sampleShadingEnable = false,
|
||||||
|
};
|
||||||
|
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
|
||||||
|
.depthTestEnable = true,
|
||||||
|
.depthWriteEnable = true,
|
||||||
|
.depthCompareOp = vk::CompareOp::eLess,
|
||||||
|
};
|
||||||
|
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
||||||
|
.blendEnable = false,
|
||||||
|
.srcColorBlendFactor = vk::BlendFactor::eSrcColor,
|
||||||
|
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor,
|
||||||
|
.colorBlendOp = vk::BlendOp::eAdd,
|
||||||
|
.srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha,
|
||||||
|
.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
|
||||||
|
.alphaBlendOp = vk::BlendOp::eAdd,
|
||||||
|
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||||
|
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||||
|
};
|
||||||
|
vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
|
||||||
|
.logicOpEnable = false,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &colorBlendAttachmentState,
|
||||||
|
};
|
||||||
|
|
||||||
|
eastl::array dynamicStates = {
|
||||||
|
vk::DynamicState::eScissor,
|
||||||
|
vk::DynamicState::eViewport,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
|
||||||
|
.dynamicStateCount = Cast<u32>(dynamicStates.size()),
|
||||||
|
.pDynamicStates = dynamicStates.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PipelineRenderingCreateInfo renderingCreateInfo = {
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachmentFormats = &swapchain->m_Format,
|
||||||
|
.depthAttachmentFormat = vk::Format::eD32Sfloat,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
||||||
|
.pNext = &renderingCreateInfo,
|
||||||
|
.stageCount = Cast<u32>(shaderStages.size()),
|
||||||
|
.pStages = shaderStages.data(),
|
||||||
|
.pVertexInputState = &vertexInputStateCreateInfo,
|
||||||
|
.pInputAssemblyState = &inputAssemblyStateCreateInfo,
|
||||||
|
.pViewportState = &viewportStateCreateInfo,
|
||||||
|
.pRasterizationState = &rasterizationStateCreateInfo,
|
||||||
|
.pMultisampleState = &multisampleStateCreateInfo,
|
||||||
|
.pDepthStencilState = &depthStencilStateCreateInfo,
|
||||||
|
.pColorBlendState = &colorBlendStateCreateInfo,
|
||||||
|
.pDynamicState = &dynamicStateCreateInfo,
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
};
|
||||||
|
vk::Pipeline pipeline;
|
||||||
|
AbortIfFailed(device->m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline));
|
||||||
|
device->SetName(pipeline, "Box Pipeline");
|
||||||
|
|
||||||
|
device->m_Device.destroy(vertexShaderModule, nullptr);
|
||||||
|
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
||||||
|
|
||||||
|
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts)};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ShaderModule
|
||||||
|
CreateShader(const Device *device, cstr shaderFile)
|
||||||
|
{
|
||||||
|
eastl::vector<u32> shaderCode = ReadFile(shaderFile);
|
||||||
|
|
||||||
|
const vk::ShaderModuleCreateInfo shaderModuleCreateInfo = {
|
||||||
|
.codeSize = shaderCode.size() * sizeof(u32),
|
||||||
|
.pCode = shaderCode.data(),
|
||||||
|
};
|
||||||
|
vk::ShaderModule shaderModule;
|
||||||
|
|
||||||
|
AbortIfFailedMV(device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule),
|
||||||
|
"Shader {} could not be created.", shaderFile);
|
||||||
|
return shaderModule;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: pipeline_utils.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pipeline.h"
|
||||||
|
|
||||||
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
|
struct RenderResourceManager;
|
||||||
|
struct Swapchain;
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
constexpr auto VERTEX_SHADER_FILE = "shader/model.vert.glsl.spv";
|
||||||
|
constexpr auto FRAGMENT_SHADER_FILE = "shader/model.frag.glsl.spv";
|
||||||
|
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
vec3 m_Position;
|
||||||
|
vec2 m_UV0;
|
||||||
|
|
||||||
|
constexpr static vk::VertexInputBindingDescription
|
||||||
|
GetBinding(const u32 binding)
|
||||||
|
{
|
||||||
|
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static eastl::array<vk::VertexInputAttributeDescription, 2>
|
||||||
|
GetAttributes(const u32 binding)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
vk::VertexInputAttributeDescription{
|
||||||
|
.location = 0,
|
||||||
|
.binding = binding,
|
||||||
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, m_Position),
|
||||||
|
},
|
||||||
|
vk::VertexInputAttributeDescription{
|
||||||
|
.location = 1,
|
||||||
|
.binding = binding,
|
||||||
|
.format = vk::Format::eR32G32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, m_UV0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||||
|
Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderResourceManager *resourceManager);
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: pipeline_utils.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "render_resource_manager.h"
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
RenderResourceManager::RenderResourceManager(const Device *device)
|
||||||
|
: m_Device(device)
|
||||||
|
{
|
||||||
|
vk::PhysicalDeviceProperties properties;
|
||||||
|
m_Device->m_PhysicalDevice.getProperties(&properties);
|
||||||
|
|
||||||
|
auto maxBufferCount = properties.limits.maxDescriptorSetStorageBuffers - 1024;
|
||||||
|
auto maxTextureCount = properties.limits.maxDescriptorSetSampledImages - 1024;
|
||||||
|
|
||||||
|
INFO("Max Buffer Count: {}", maxBufferCount);
|
||||||
|
INFO("Max Texture Count: {}", maxTextureCount);
|
||||||
|
|
||||||
|
m_Buffers.resize(maxBufferCount);
|
||||||
|
m_Textures.resize(maxTextureCount);
|
||||||
|
|
||||||
|
eastl::array poolSizes = {
|
||||||
|
vk::DescriptorPoolSize{.type = vk::DescriptorType::eStorageBuffer, .descriptorCount = maxBufferCount},
|
||||||
|
vk::DescriptorPoolSize{.type = vk::DescriptorType::eSampledImage, .descriptorCount = maxTextureCount},
|
||||||
|
};
|
||||||
|
vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
||||||
|
.flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
|
||||||
|
.maxSets = 4,
|
||||||
|
.poolSizeCount = Cast<u32>(poolSizes.size()),
|
||||||
|
.pPoolSizes = poolSizes.data(),
|
||||||
|
};
|
||||||
|
AbortIfFailed(device->m_Device.createDescriptorPool(&poolCreateInfo, nullptr, &m_DescriptorPool));
|
||||||
|
|
||||||
|
eastl::array descriptorLayoutBindings = {
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = 0,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = Cast<u32>(m_Buffers.size()),
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
|
},
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eSampledImage,
|
||||||
|
.descriptorCount = Cast<u32>(m_Textures.size()),
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||||
|
.flags = vk::DescriptorSetLayoutCreateFlagBits::eUpdateAfterBindPool,
|
||||||
|
.bindingCount = Cast<u32>(descriptorLayoutBindings.size()),
|
||||||
|
.pBindings = descriptorLayoutBindings.data(),
|
||||||
|
};
|
||||||
|
AbortIfFailed(device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &m_SetLayout));
|
||||||
|
|
||||||
|
// One descriptor is enough. Updating it at any time is safe. (Update until submit, data held when pending)
|
||||||
|
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_descriptor_indexing.html
|
||||||
|
// https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/extensions/VK_EXT_descriptor_indexing.adoc
|
||||||
|
const vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
||||||
|
.descriptorPool = m_DescriptorPool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = &m_SetLayout,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::~RenderResourceManager()
|
||||||
|
{
|
||||||
|
for (auto &buffer : m_Buffers)
|
||||||
|
{
|
||||||
|
buffer.Destroy(m_Device);
|
||||||
|
}
|
||||||
|
for (auto &image : m_Textures)
|
||||||
|
{
|
||||||
|
image.Destroy(m_Device);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Device->m_Device.destroy(m_TextureUpdate, nullptr);
|
||||||
|
m_Device->m_Device.destroy(m_BufferUpdate, nullptr);
|
||||||
|
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||||
|
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: pipeline_utils.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#include <EASTL/array.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
struct Texture;
|
||||||
|
struct UniformBuffer;
|
||||||
|
|
||||||
|
struct Handle
|
||||||
|
{
|
||||||
|
u16 m_Index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BufferHandle : Handle
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureHandle : Handle
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderResourceManager
|
||||||
|
{
|
||||||
|
const Device *m_Device;
|
||||||
|
|
||||||
|
vk::DescriptorPool m_DescriptorPool;
|
||||||
|
vk::DescriptorSetLayout m_SetLayout;
|
||||||
|
vk::DescriptorSet m_DescriptorSet;
|
||||||
|
|
||||||
|
vk::DescriptorUpdateTemplate m_BufferUpdate;
|
||||||
|
vk::DescriptorUpdateTemplate m_TextureUpdate;
|
||||||
|
|
||||||
|
eastl::vector<UniformBuffer> m_Buffers;
|
||||||
|
eastl::vector<Texture> m_Textures;
|
||||||
|
// TODO: eastl::vector<StorageTexture> m_Textures;
|
||||||
|
|
||||||
|
// UniformBuffer *Allocate();
|
||||||
|
// UniformBuffer *Fetch(UniformHandle handle);
|
||||||
|
// void Commit(UniformHandle handle);
|
||||||
|
// Texture *Allocate();
|
||||||
|
// Texture *Fetch(TextureHandle handle);
|
||||||
|
// void Commit(TextureHandle handle);
|
||||||
|
|
||||||
|
// Ctor/Dtor
|
||||||
|
explicit RenderResourceManager(const Device *device);
|
||||||
|
~RenderResourceManager();
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#version 450
|
||||||
|
#pragma shader_stage(fragment)
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 inUV;
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(set = 1, binding = 1) uniform sampler2D tex;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(texture(tex, inUV).rgb, 1.0f);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#version 450
|
||||||
|
#pragma shader_stage(vertex)
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 position;
|
||||||
|
layout(location = 1) in vec2 uv0;
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 outUV;
|
||||||
|
|
||||||
|
//layout(std140, set=0, binding=0) readonly buffer buffers;
|
||||||
|
layout(set = 0, binding = 1) uniform texture2D textures[];
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform Camera {
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
mat4 proj;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outUV = uv0;
|
||||||
|
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(position.xyz, 1.0f);
|
||||||
|
// outColor = vec3(0.5f, 0.3f, 0.1f);
|
||||||
|
}
|
||||||
|
|
@ -5,3 +5,4 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
add_subdirectory("00_util")
|
add_subdirectory("00_util")
|
||||||
add_subdirectory("01_triangle")
|
add_subdirectory("01_triangle")
|
||||||
add_subdirectory("02_box")
|
add_subdirectory("02_box")
|
||||||
|
add_subdirectory("03_model_render")
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
"eastl",
|
||||||
"fmt",
|
"fmt",
|
||||||
"glfw3",
|
"glfw3",
|
||||||
"glm",
|
"glm",
|
||||||
"scottt-debugbreak",
|
"scottt-debugbreak",
|
||||||
"vulkan-memory-allocator",
|
"tinygltf",
|
||||||
"eastl"
|
"vulkan-memory-allocator"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue