631 lines
23 KiB
C++
631 lines
23 KiB
C++
// =============================================
|
|
// Aster: model_render.cpp
|
|
// Copyright (c) 2020-2025 Anish Bhobe
|
|
// =============================================
|
|
|
|
#include "aster/aster.h"
|
|
|
|
#include "aster/core/buffer.h"
|
|
#include "aster/core/constants.h"
|
|
#include "aster/core/device.h"
|
|
#include "aster/core/image.h"
|
|
#include "aster/core/instance.h"
|
|
#include "aster/core/physical_device.h"
|
|
#include "aster/core/pipeline.h"
|
|
#include "aster/core/swapchain.h"
|
|
#include "aster/core/window.h"
|
|
#include "aster/util/files.h"
|
|
|
|
#include "aster/systems/commit_manager.h"
|
|
#include "aster/systems/rendering_device.h"
|
|
|
|
#include "asset_loader.h"
|
|
#include "light_manager.h"
|
|
|
|
#include "gui.h"
|
|
#include "ibl_helpers.h"
|
|
|
|
#include <EASTL/array.h>
|
|
#include <tiny_gltf.h>
|
|
|
|
constexpr auto PIPELINE_CACHE_FILE = "PipelineCacheData.bin";
|
|
constexpr auto MODEL_FILE = "model/DamagedHelmet.glb";
|
|
constexpr auto BACKDROP_FILE = "image/photo_studio_loft_hall_4k.hdr";
|
|
|
|
constexpr auto MODEL_SHADER_FILE = "model";
|
|
constexpr auto BACKGROUND_SHADER_FILE = "background";
|
|
|
|
constexpr u32 INIT_WIDTH = 1280;
|
|
constexpr u32 INIT_HEIGHT = 720;
|
|
|
|
struct Camera
|
|
{
|
|
mat4 m_View;
|
|
mat4 m_Perspective;
|
|
mat4 m_InverseView;
|
|
mat4 m_InversePerspective;
|
|
vec3 m_Position;
|
|
f32 m_PositionHomogenousPad_ = 1.0f;
|
|
|
|
void
|
|
CalculateInverses()
|
|
{
|
|
m_InverseView = inverse(m_View);
|
|
m_InversePerspective = inverse(m_Perspective);
|
|
}
|
|
};
|
|
|
|
struct CameraController
|
|
{
|
|
constexpr static auto UP = vec3(0.0f, 1.0f, 0.0f);
|
|
|
|
f32 m_Fov;
|
|
f32 m_Pitch;
|
|
f32 m_Yaw;
|
|
f32 m_AspectRatio;
|
|
|
|
Camera m_Camera;
|
|
|
|
CameraController(const vec3 &position, const vec3 &target, const f32 vFov, const f32 aspectRatio)
|
|
: m_Fov(vFov)
|
|
, m_Pitch{0.0f}
|
|
, m_Yaw{0.0f}
|
|
, m_AspectRatio{aspectRatio}
|
|
, m_Camera{
|
|
.m_View = lookAt(position, target, UP),
|
|
.m_Perspective = glm::perspective(vFov, aspectRatio, 0.1f, 100.0f),
|
|
.m_Position = position,
|
|
}
|
|
{
|
|
const vec3 dir = normalize(target - vec3(position));
|
|
m_Pitch = asin(dir.y);
|
|
m_Yaw = acos(-dir.z / sqrt(1.0f - dir.y * dir.y));
|
|
m_Camera.CalculateInverses();
|
|
}
|
|
|
|
void
|
|
SetAspectRatio(const f32 aspectRatio)
|
|
{
|
|
m_AspectRatio = aspectRatio;
|
|
m_Camera.m_Perspective = glm::perspective(m_Fov, aspectRatio, 0.1f, 100.0f);
|
|
|
|
m_Camera.CalculateInverses();
|
|
}
|
|
|
|
void
|
|
SetPosition(const vec3 &position)
|
|
{
|
|
m_Camera.m_Position = vec4(position, 1.0f);
|
|
|
|
f32 cosPitch = cos(m_Pitch);
|
|
const auto target = vec3(sin(m_Yaw) * cosPitch, sin(m_Pitch), -cos(m_Yaw) * cosPitch);
|
|
m_Camera.m_View = lookAt(position, position + target, UP);
|
|
|
|
m_Camera.CalculateInverses();
|
|
}
|
|
|
|
void
|
|
SetPitchYaw(f32 pitch, f32 yaw)
|
|
{
|
|
m_Pitch = pitch;
|
|
m_Yaw = yaw;
|
|
|
|
f32 cosPitch = cos(m_Pitch);
|
|
const auto target = vec3(sin(m_Yaw) * cosPitch, sin(m_Pitch), -cos(m_Yaw) * cosPitch);
|
|
const vec3 position = m_Camera.m_Position;
|
|
m_Camera.m_View = lookAt(position, position + target, UP);
|
|
|
|
m_Camera.CalculateInverses();
|
|
}
|
|
|
|
void
|
|
SetLookAt(const vec3 &target)
|
|
{
|
|
const vec3 dir = normalize(target - m_Camera.m_Position);
|
|
m_Pitch = acos(dir.y);
|
|
m_Yaw = acos(dir.z / sqrt(1.0f - dir.y * dir.y));
|
|
m_Camera.m_View = lookAt(m_Camera.m_Position, m_Camera.m_Position + target, UP);
|
|
|
|
m_Camera.CalculateInverses();
|
|
}
|
|
};
|
|
|
|
int
|
|
main(int, char **)
|
|
{
|
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
|
|
|
Window window = {"ModelRender (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
|
|
|
Features enabledDeviceFeatures = {
|
|
.m_Vulkan10Features = {.samplerAnisotropy = true, .shaderInt16 = 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,
|
|
.timelineSemaphore = true,
|
|
.bufferDeviceAddress = true,
|
|
.bufferDeviceAddressCaptureReplay = true,
|
|
},
|
|
.m_Vulkan13Features =
|
|
{
|
|
.synchronization2 = true,
|
|
.dynamicRendering = true,
|
|
},
|
|
};
|
|
|
|
auto pipelineCacheData = ReadFileBytes(PIPELINE_CACHE_FILE, false);
|
|
systems::RenderingDevice device{{
|
|
.m_Window = window,
|
|
.m_Features = enabledDeviceFeatures,
|
|
.m_AppName = "ModelRender",
|
|
.m_AppVersion = VERSION,
|
|
.m_PipelineCacheData = pipelineCacheData,
|
|
.m_ShaderSearchPaths = {"shader/"},
|
|
}};
|
|
|
|
AssetLoader assetLoader{device};
|
|
LightManager lightManager{device};
|
|
|
|
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
|
auto environmentHdri = assetLoader.LoadHdrImage(BACKDROP_FILE);
|
|
auto envHdriHandle = device.m_CommitManager->CommitTexture(environmentHdri);
|
|
|
|
auto environment = CreateCubeFromHdrEnv(assetLoader, 512, envHdriHandle);
|
|
|
|
auto attachmentFormat = device.m_Swapchain.m_Format;
|
|
|
|
Pipeline pipeline;
|
|
if (auto result = device.CreateGraphicsPipeline(pipeline, {
|
|
.m_Shaders = {{
|
|
.m_ShaderFile = MODEL_SHADER_FILE,
|
|
.m_EntryPoints = {"vsmain", "fsmain"},
|
|
}},
|
|
.m_Name = "Primary",
|
|
}))
|
|
{
|
|
ERROR("Could not create model pipeline. Cause: {}", result.What()) THEN_ABORT(result.Value());
|
|
}
|
|
|
|
Pipeline backgroundPipeline;
|
|
if (auto result = device.CreateGraphicsPipeline(
|
|
backgroundPipeline, {
|
|
.m_Shaders = {{
|
|
.m_ShaderFile = BACKGROUND_SHADER_FILE,
|
|
.m_EntryPoints = {"vsmain", "fsmain"},
|
|
}},
|
|
.m_DepthTest = systems::GraphicsPipelineCreateInfo::DepthTest::eReadOnly,
|
|
.m_DepthOp = systems::GraphicsPipelineCreateInfo::CompareOp::eLessThanOrEqualTo,
|
|
.m_Name = "Background",
|
|
}))
|
|
{
|
|
ERROR("Could not create background pipeline. Cause: {}", result.What()) THEN_ABORT(result.Value());
|
|
}
|
|
|
|
lightManager.AddPoint(vec3{-5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
|
lightManager.AddPoint(vec3{5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
|
lightManager.AddPoint(vec3{-5.0f, 5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
|
lightManager.AddPoint(vec3{5.0f, 5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
|
|
|
lightManager.Update();
|
|
|
|
vk::Extent2D internalResolution = {1920, 1080};
|
|
|
|
auto swapchainSize = device.GetSwapchainSize();
|
|
|
|
CameraController cameraController = {vec3{0.0f, 0.0f, 2.0f}, vec3{0.0f}, 70_deg,
|
|
static_cast<f32>(swapchainSize.m_Width) /
|
|
static_cast<f32>(swapchainSize.m_Height)};
|
|
|
|
auto cameraBuffer = device.CreateStorageBuffer(sizeof cameraController.m_Camera, "Camera Info");
|
|
auto cameraBufferId = device.m_CommitManager->CommitBuffer(cameraBuffer);
|
|
auto lightManagerBuffer =
|
|
device.CreateStorageBuffer(sizeof environment + sizeof lightManager.m_MetaInfo, "Light Info");
|
|
auto lightsBufferId = device.m_CommitManager->CommitBuffer(lightManagerBuffer);
|
|
lightManagerBuffer->Write(0, sizeof environment, &environment);
|
|
lightManagerBuffer->Write(sizeof environment, sizeof lightManager.m_MetaInfo, &lightManager.m_MetaInfo);
|
|
|
|
// Persistent variables
|
|
vk::Viewport viewport = {
|
|
.x = 0,
|
|
.y = static_cast<f32>(internalResolution.height),
|
|
.width = static_cast<f32>(internalResolution.width),
|
|
.height = -static_cast<f32>(internalResolution.height),
|
|
.minDepth = 0.0,
|
|
.maxDepth = 1.0,
|
|
};
|
|
|
|
vk::ImageSubresourceRange subresourceRange = {
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
};
|
|
|
|
vk::ImageMemoryBarrier2 attachmentPreRenderBarrier = {
|
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
.srcAccessMask = vk::AccessFlagBits2::eTransferRead,
|
|
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
.oldLayout = vk::ImageLayout::eUndefined,
|
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
|
|
vk::ImageMemoryBarrier2 attachmentRenderToBlitBarrier = {
|
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
.dstStageMask = vk::PipelineStageFlagBits2::eBlit,
|
|
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
|
|
// Dependency from Acquire to Blit
|
|
vk::ImageMemoryBarrier2 swapchainPreBlitBarrier = {
|
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
|
.dstStageMask = vk::PipelineStageFlagBits2::eBlit,
|
|
.dstAccessMask = vk::AccessFlagBits2::eTransferRead | vk::AccessFlagBits2::eTransferWrite,
|
|
.oldLayout = vk::ImageLayout::eUndefined,
|
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
|
|
// Execution dependency between blit and GUI render.
|
|
vk::ImageMemoryBarrier2 swapchainBlitToGuiBarrier = {
|
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
|
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentRead,
|
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
|
|
vk::ImageMemoryBarrier2 swapchainPrePresentBarrier = {
|
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
|
.dstAccessMask = vk::AccessFlagBits2::eNone,
|
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
|
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
|
.subresourceRange = subresourceRange,
|
|
};
|
|
|
|
eastl::fixed_vector<Ref<ImageView>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
|
eastl::fixed_vector<Ref<ImageView>, MAX_FRAMES_IN_FLIGHT> attachmentImages;
|
|
|
|
for (u32 index = 0; index < MAX_FRAMES_IN_FLIGHT; ++index)
|
|
{
|
|
auto name = fmt::format("Depth Frame{}", index);
|
|
depthImages.emplace_back(device.CreateDepthStencilImageWithView({
|
|
.m_Extent = internalResolution,
|
|
.m_Name = name.c_str(),
|
|
}));
|
|
|
|
name = fmt::format("Attachment0 Frame{}", index);
|
|
attachmentImages.emplace_back(device.CreateAttachmentWithView({
|
|
.m_Format = attachmentFormat,
|
|
.m_Extent = internalResolution,
|
|
.m_Name = name.c_str(),
|
|
}));
|
|
}
|
|
|
|
gui::Init(device, window);
|
|
bool rotating = false;
|
|
bool lockToScreen = true;
|
|
bool showDiffuse = false;
|
|
bool useDiffuse = true;
|
|
bool showPrefilter = false;
|
|
bool useSpecular = true;
|
|
|
|
constexpr static u32 USE_DIFFUSE_BIT = 1;
|
|
constexpr static u32 USE_SPECULAR_BIT = 1 << 1;
|
|
constexpr static u32 SHOW_DIFFUSE_BIT = 1 << 2;
|
|
constexpr static u32 SHOW_PREFILTER_BIT = 1 << 3;
|
|
|
|
i32 height = static_cast<i32>(internalResolution.height);
|
|
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
|
f32 camYaw = glm::degrees(cameraController.m_Yaw);
|
|
vec3 camPosition = cameraController.m_Camera.m_Position;
|
|
vk::Extent2D inputResolution = internalResolution;
|
|
|
|
device.RegisterResizeCallback([&cameraController](vk::Extent2D const extent) {
|
|
cameraController.SetAspectRatio(static_cast<f32>(extent.width) / static_cast<f32>(extent.height));
|
|
});
|
|
|
|
Time::Init();
|
|
|
|
INFO("Starting loop");
|
|
while (window.Poll())
|
|
{
|
|
Time::Update();
|
|
|
|
gui::StartBuild();
|
|
|
|
gui::Begin("Settings");
|
|
gui::Text("Window Resolution: %ux%u", swapchainSize.m_Width, swapchainSize.m_Height);
|
|
gui::Text("Render Resolution: %ux%u", internalResolution.width, internalResolution.height);
|
|
gui::Checkbox("Lock Resolution to Window", &lockToScreen);
|
|
if (!lockToScreen)
|
|
{
|
|
if (gui::InputInt("FrameBuffer Height", &height, 1, 10))
|
|
{
|
|
height = eastl::clamp(height, 64, 4320);
|
|
}
|
|
|
|
inputResolution.height = height;
|
|
inputResolution.width =
|
|
static_cast<i32>(cameraController.m_AspectRatio * static_cast<f32>(inputResolution.height));
|
|
|
|
if (gui::Button("Change Resolution"))
|
|
{
|
|
if (inputResolution.width != internalResolution.width ||
|
|
inputResolution.height != internalResolution.height)
|
|
{
|
|
internalResolution = inputResolution;
|
|
viewport.width = static_cast<f32>(internalResolution.width);
|
|
viewport.height = -static_cast<f32>(internalResolution.height);
|
|
viewport.y = static_cast<f32>(internalResolution.height);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (swapchainSize.m_Width != internalResolution.width ||
|
|
swapchainSize.m_Height != internalResolution.height)
|
|
{
|
|
internalResolution = swapchainSize;
|
|
viewport.width = static_cast<f32>(internalResolution.width);
|
|
viewport.height = -static_cast<f32>(internalResolution.height);
|
|
viewport.y = static_cast<f32>(internalResolution.height);
|
|
}
|
|
}
|
|
gui::Separator();
|
|
gui::Text("Delta: %0.6f ms", 1000.0f * Time::m_Delta);
|
|
gui::Text("FPS: %0.6f", 1.0f / Time::m_Delta);
|
|
gui::Separator();
|
|
gui::PushItemWidth(100);
|
|
bool yawChange = gui::DragFloat("Camera Yaw", &camYaw);
|
|
bool pitchChange = gui::DragFloat("Camera Pitch", &camPitch, 1, -89.0f, 89.0f);
|
|
if (yawChange || pitchChange)
|
|
{
|
|
camYaw = camYaw - floor((camYaw + 180.0f) / 360.0f) * 360.0f;
|
|
cameraController.SetPitchYaw(glm::radians(camPitch), glm::radians(camYaw));
|
|
}
|
|
if (gui::InputFloat3("Camera Position", reinterpret_cast<f32 *>(&camPosition)))
|
|
{
|
|
cameraController.SetPosition(camPosition);
|
|
}
|
|
gui::Separator();
|
|
gui::Text("IBL");
|
|
gui::Checkbox("Show DiffIrr", &showDiffuse);
|
|
gui::Checkbox("Use DiffIrr", &useDiffuse);
|
|
gui::Checkbox("Show Prefilter", &showPrefilter);
|
|
gui::Checkbox("Use Specular", &useSpecular);
|
|
gui::Separator();
|
|
gui::Checkbox("Rotate", &rotating);
|
|
gui::PopItemWidth();
|
|
if (gui::Button("Exit"))
|
|
{
|
|
window.RequestExit();
|
|
}
|
|
gui::End();
|
|
|
|
gui::EndBuild();
|
|
|
|
if (rotating)
|
|
{
|
|
model.SetModelTransform(
|
|
rotate(model.GetModelTransform(), static_cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)));
|
|
}
|
|
model.Update();
|
|
cameraController.m_Camera.CalculateInverses();
|
|
cameraBuffer->Write(0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
|
|
|
auto ¤tFrame = device.GetNextFrame();
|
|
|
|
auto context = currentFrame.CreateGraphicsContext();
|
|
|
|
auto ¤tDepthImage = depthImages[currentFrame.m_FrameIdx];
|
|
auto ¤tAttachment = attachmentImages[currentFrame.m_FrameIdx];
|
|
|
|
if (currentAttachment->m_Extent.width != internalResolution.width ||
|
|
currentAttachment->m_Extent.height != internalResolution.height)
|
|
{
|
|
auto name = fmt::format("Depth Frame{}", currentFrame.m_FrameIdx);
|
|
currentDepthImage = device.CreateDepthStencilImageWithView({
|
|
.m_Extent = internalResolution,
|
|
.m_Name = name.c_str(),
|
|
});
|
|
|
|
name = fmt::format("Attachment0 Frame{}", currentFrame.m_FrameIdx);
|
|
currentAttachment = device.CreateAttachmentWithView({
|
|
.m_Format = attachmentFormat,
|
|
.m_Extent = internalResolution,
|
|
.m_Name = name.c_str(),
|
|
});
|
|
}
|
|
|
|
vk::Image currentSwapchainImage = currentFrame.m_SwapchainImage;
|
|
|
|
vk::ImageView currentDepthImageView = currentDepthImage->m_View;
|
|
vk::Image currentImage = currentAttachment->m_Image->m_Image;
|
|
vk::ImageView currentImageView = currentAttachment->m_View;
|
|
|
|
attachmentPreRenderBarrier.image = currentImage;
|
|
attachmentRenderToBlitBarrier.image = currentImage;
|
|
swapchainPreBlitBarrier.image = currentSwapchainImage;
|
|
swapchainBlitToGuiBarrier.image = currentSwapchainImage;
|
|
swapchainPrePresentBarrier.image = currentSwapchainImage;
|
|
|
|
context.Begin();
|
|
|
|
eastl::array firstBarriers = {attachmentPreRenderBarrier, swapchainPreBlitBarrier};
|
|
context.Dependency({
|
|
.imageMemoryBarrierCount = static_cast<u32>(firstBarriers.size()),
|
|
.pImageMemoryBarriers = firstBarriers.data(),
|
|
});
|
|
|
|
// 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 = ToExtent2D(currentAttachment->m_Extent)},
|
|
.layerCount = 1,
|
|
.colorAttachmentCount = static_cast<u32>(attachmentInfos.size()),
|
|
.pColorAttachments = attachmentInfos.data(),
|
|
.pDepthAttachment = &depthAttachment,
|
|
};
|
|
|
|
context.BeginRendering(renderingInfo);
|
|
|
|
context.SetViewport(viewport);
|
|
|
|
context.BindIndexBuffer(model.m_IndexBuffer);
|
|
|
|
context.BindPipeline(pipeline);
|
|
|
|
u32 flags = 0;
|
|
if (useSpecular)
|
|
{
|
|
flags |= USE_SPECULAR_BIT;
|
|
}
|
|
if (useDiffuse)
|
|
{
|
|
flags |= USE_DIFFUSE_BIT;
|
|
}
|
|
if (showPrefilter)
|
|
{
|
|
flags |= SHOW_PREFILTER_BIT;
|
|
}
|
|
if (showDiffuse)
|
|
{
|
|
flags |= SHOW_DIFFUSE_BIT;
|
|
}
|
|
|
|
u32 pcbOffset = 0;
|
|
context.PushConstantBlock(model.m_Handles);
|
|
pcbOffset += sizeof model.m_Handles;
|
|
context.PushConstantBlock(pcbOffset, cameraBufferId);
|
|
pcbOffset += sizeof cameraBufferId;
|
|
context.PushConstantBlock(pcbOffset, lightsBufferId);
|
|
pcbOffset += sizeof lightsBufferId;
|
|
context.PushConstantBlock(pcbOffset, flags);
|
|
pcbOffset += sizeof flags;
|
|
|
|
for (auto &prim : model.m_MeshPrimitives)
|
|
{
|
|
u32 innerPcbOffset = pcbOffset;
|
|
context.PushConstantBlock(innerPcbOffset, prim.m_MaterialIdx);
|
|
innerPcbOffset += sizeof prim.m_MaterialIdx;
|
|
context.PushConstantBlock(innerPcbOffset, prim.m_TransformIdx);
|
|
innerPcbOffset += sizeof prim.m_TransformIdx;
|
|
context.DrawIndexed(prim.m_IndexCount, prim.m_FirstIndex, prim.m_VertexOffset);
|
|
}
|
|
|
|
context.BindPipeline(backgroundPipeline);
|
|
context.Draw(3);
|
|
|
|
context.EndRendering();
|
|
|
|
context.Dependency({.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &attachmentRenderToBlitBarrier});
|
|
|
|
vk::ImageBlit2 blitRegion = {
|
|
.srcSubresource =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.mipLevel = 0,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
.srcOffsets =
|
|
std::array{
|
|
vk::Offset3D{0, 0, 0},
|
|
ToOffset3D(currentAttachment->m_Extent),
|
|
},
|
|
.dstSubresource =
|
|
{
|
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
.mipLevel = 0,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
.dstOffsets =
|
|
std::array{
|
|
vk::Offset3D{0, 0, 0},
|
|
vk::Offset3D{static_cast<i32>(swapchainSize.m_Width), static_cast<i32>(swapchainSize.m_Height), 1},
|
|
},
|
|
};
|
|
|
|
vk::BlitImageInfo2 blit = {
|
|
.srcImage = currentImage,
|
|
.srcImageLayout = vk::ImageLayout::eTransferSrcOptimal,
|
|
.dstImage = currentSwapchainImage,
|
|
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
.regionCount = 1,
|
|
.pRegions = &blitRegion,
|
|
.filter = vk::Filter::eLinear,
|
|
};
|
|
|
|
context.Blit(blit);
|
|
|
|
context.Dependency({.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &swapchainBlitToGuiBarrier});
|
|
|
|
gui::Draw(currentFrame, context);
|
|
|
|
context.Dependency({.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &swapchainPrePresentBarrier});
|
|
|
|
context.End();
|
|
|
|
device.Present(currentFrame, context);
|
|
}
|
|
|
|
device.WaitIdle();
|
|
|
|
pipelineCacheData = device.DumpPipelineCache();
|
|
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
|
|
|
gui::Destroy(device);
|
|
|
|
return 0;
|
|
} |