feat: basic shadow map + renderdoc labels

This commit is contained in:
2026-10-11 01:02:26 +02:00
parent 4bf87bd91b
commit 95d1497169
36 changed files with 880 additions and 228 deletions
+1
View File
@@ -50,6 +50,7 @@ set(SRC_FILES
"src/Graphics/Pipelines/QuadRendererPass.cpp" "src/Graphics/Pipelines/QuadRendererPass.cpp"
"src/Graphics/Pipelines/SkyboxPipeline.cpp" "src/Graphics/Pipelines/SkyboxPipeline.cpp"
"src/Graphics/Pipelines/LightCullingPipeline.cpp" "src/Graphics/Pipelines/LightCullingPipeline.cpp"
"src/Graphics/Pipelines/ShadowMapPipeline.cpp"
"src/Graphics/Pipelines/SkinningPipeline.cpp" "src/Graphics/Pipelines/SkinningPipeline.cpp"
"src/Graphics/Pipelines/ImguiPass.cpp" "src/Graphics/Pipelines/ImguiPass.cpp"
+4
View File
@@ -35,6 +35,10 @@ vec4 sampleTextureCubeLinear(uint texID, vec3 p) {
return texture(nonuniformEXT(samplerCube(textureCubes[texID], samplers[LINEAR_SAMPLER_ID])), p); return texture(nonuniformEXT(samplerCube(textureCubes[texID], samplers[LINEAR_SAMPLER_ID])), p);
} }
float sampleTexture2DShadow(uint texID, vec3 p) {
return texture(nonuniformEXT(sampler2DShadow(textures[texID], samplers[SHADOW_SAMPLER_ID])), p);
}
float sampleTextureArrayShadow(uint texID, vec4 p) { float sampleTextureArrayShadow(uint texID, vec4 p) {
return texture(nonuniformEXT(sampler2DArrayShadow(textureArrays[texID], samplers[SHADOW_SAMPLER_ID])), p); return texture(nonuniformEXT(sampler2DArrayShadow(textureArrays[texID], samplers[SHADOW_SAMPLER_ID])), p);
} }
+2 -2
View File
@@ -44,7 +44,7 @@ float calculateSpotAttenuation(Light light, vec3 l)
} }
vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v, vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v,
vec3 diffuseColor, float roughness, float metallic, vec3 f0) vec3 diffuseColor, float roughness, float metallic, vec3 f0, float occlusion)
{ {
vec3 l; vec3 l;
float attenuation = 1.0; float attenuation = 1.0;
@@ -80,7 +80,7 @@ vec3 calculateLight(Light light, vec3 fragPos, vec3 n, vec3 v,
vec3 kd = (vec3(1.0) - F) * (1.0 - metallic); vec3 kd = (vec3(1.0) - F) * (1.0 - metallic);
vec3 diffuse = kd * diffuseColor / PI; vec3 diffuse = kd * diffuseColor / PI;
return (diffuse + specular) * light.color * light.intensity * attenuation * NoL; return (diffuse + specular) * light.color * light.intensity * attenuation * NoL * occlusion;
} }
// blue -> green -> red, used to visualise how many lights a tile has // blue -> green -> red, used to visualise how many lights a tile has
+2 -1
View File
@@ -27,7 +27,8 @@ struct Light {
float spotInnerCos; float spotInnerCos;
float spotOuterCos; float spotOuterCos;
vec2 padding; uint castShadows;
float padding;
}; };
layout (buffer_reference, std430) readonly buffer LightsBuffer { layout (buffer_reference, std430) readonly buffer LightsBuffer {
+11 -1
View File
@@ -6,6 +6,7 @@
#include "scene_data.glsl" #include "scene_data.glsl"
#include "mesh_pcs.glsl" #include "mesh_pcs.glsl"
#include "lighting.glsl" #include "lighting.glsl"
#include "shadows.glsl"
layout (location = 0) in vec3 inPos; layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV; layout (location = 1) in vec2 inUV;
@@ -69,8 +70,17 @@ void main()
uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i]; uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i];
Light light = pcs.sceneData.lights.data[lightIndex]; Light light = pcs.sceneData.lights.data[lightIndex];
float occlusion = 1.0;
if (light.castShadows != 0) {
occlusion = calculateDirectionalShadow(
fragPos, n,
pcs.sceneData.lightViewProj,
pcs.sceneData.shadowMapId,
pcs.sceneData.shadowNormalOffset);
}
fragColor += calculateLight(light, fragPos, n, v, fragColor += calculateLight(light, fragPos, n, v,
diffuseColor, roughness, metallic, f0); diffuseColor, roughness, metallic, f0, occlusion);
} }
// emissive // emissive
@@ -33,7 +33,12 @@ layout (buffer_reference, scalar) readonly buffer SceneDataBuffer {
uint numLights; uint numLights;
uint tileCountX; uint tileCountX;
uint debugLightHeatmap; uint debugLightHeatmap;
// directional shadows
uint shadowMapId;
float shadowNormalOffset;
uint padding; uint padding;
mat4 lightViewProj;
} sceneDataBuffer; } sceneDataBuffer;
#endif // SCENE_DATA_GLSL #endif // SCENE_DATA_GLSL
+12
View File
@@ -0,0 +1,12 @@
#version 460
#extension GL_GOOGLE_include_directive : require
#include "mesh_pcs.glsl"
void main()
{
Vertex v = pcs.vertexBuffer.vertices[gl_VertexIndex];
gl_Position = pcs.sceneData.lightViewProj * pcs.transform * vec4(v.position, 1.0f);
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef SHADOWS_GLSL
#define SHADOWS_GLSL
// expects bindless.glsl to be included before this file (it has no include guard)
// Returns 1.0 when fully lit, 0.0 when fully in shadow
float calculateDirectionalShadow(vec3 fragPos, vec3 n, mat4 lightViewProj, uint shadowMapID, float normalOffset)
{
// pushing the sample point along the normal hides most of the shadow acne
vec4 lightClip = lightViewProj * vec4(fragPos + n * normalOffset, 1.0);
vec3 lightNDC = lightClip.xyz / lightClip.w;
vec2 uv = lightNDC.xy * 0.5 + 0.5;
// outside the shadow map counts as lit
if (any(lessThan(uv, vec2(0.0))) || any(greaterThan(uv, vec2(1.0))) || lightNDC.z > 1.0) {
return 1.0;
}
vec2 texelSize = 1.0 / vec2(textureSize(sampler2DShadow(textures[shadowMapID], samplers[SHADOW_SAMPLER_ID]), 0));
// 3x3 PCF, every tap is already bilinearly filtered by the compare sampler
float shadowed = 0.0;
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
shadowed += sampleTexture2DShadow(shadowMapID, vec3(uv + vec2(x, y) * texelSize, lightNDC.z));
}
}
// the shadow sampler compares with GREATER_OR_EQUAL (it was set up for reversed Z),
// with regular depth that returns 1 when the fragment is behind the occluder
return 1.0 - shadowed / 9.0;
}
#endif // SHADOWS_GLSL
@@ -39,6 +39,9 @@ public:
[[nodiscard]] float GetInnerConeAngle() const { return m_InnerConeAngle; } [[nodiscard]] float GetInnerConeAngle() const { return m_InnerConeAngle; }
[[nodiscard]] float GetOuterConeAngle() const { return m_OuterConeAngle; } [[nodiscard]] float GetOuterConeAngle() const { return m_OuterConeAngle; }
void SetCastShadows(bool castShadows) { m_CastShadows = castShadows; }
[[nodiscard]] bool GetCastShadows() const { return m_CastShadows; }
private: private:
LightType m_Type{LightType::Point}; LightType m_Type{LightType::Point};
glm::vec3 m_Color{1.0f}; glm::vec3 m_Color{1.0f};
@@ -46,6 +49,7 @@ private:
float m_Range{10.0f}; float m_Range{10.0f};
float m_InnerConeAngle{0.35f}; float m_InnerConeAngle{0.35f};
float m_OuterConeAngle{0.5f}; float m_OuterConeAngle{0.5f};
bool m_CastShadows{false};
}; };
#endif // LIGHTCOMPONENT_H #endif // LIGHTCOMPONENT_H
+5 -1
View File
@@ -25,6 +25,9 @@ struct Light {
float innerConeAngle{0.35f}; float innerConeAngle{0.35f};
float outerConeAngle{0.5f}; float outerConeAngle{0.5f};
// directional lights only, the first one submitted each frame gets the shadow map
bool castShadows{false};
}; };
struct GPULight { struct GPULight {
@@ -39,7 +42,8 @@ struct GPULight {
float spotInnerCos; float spotInnerCos;
float spotOuterCos; float spotOuterCos;
glm::vec2 padding; std::uint32_t castShadows;
float padding;
}; };
static_assert(sizeof(GPULight) == 64, "GPULight must match the struct in lights.glsl"); static_assert(sizeof(GPULight) == 64, "GPULight must match the struct in lights.glsl");
@@ -0,0 +1,65 @@
#ifndef SHADOWMAPPIPELINE_H
#define SHADOWMAPPIPELINE_H
#include <cstdint>
#include <memory>
#include <vector>
#include <glm/glm.hpp>
#include <vulkan/vulkan.h>
#include <destrum/Graphics/Pipeline.h>
#include <destrum/Graphics/ids.h>
#include <destrum/Graphics/MeshDrawCommand.h>
#include <destrum/Graphics/Resources/Buffer.h>
class GfxDevice;
class RenderResources;
// Renders the depth of the scene as seen from a directional light, centered around the camera
class ShadowMapPipeline final
{
public:
static constexpr std::uint32_t SHADOW_MAP_SIZE = 2048;
void init(GfxDevice& gfxDevice, RenderResources& resources);
void cleanup(VkDevice device);
void draw(
VkCommandBuffer cmd,
const RenderResources& resources,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands);
[[nodiscard]] glm::mat4 calculateLightViewProj(const glm::vec3& lightDirection, const glm::vec3& center) const;
[[nodiscard]] ImageID getShadowMapId() const { return shadowMapId; }
[[nodiscard]] float getNormalOffset() const;
// half the width of the area around the camera that receives shadows
void setShadowDistance(float distance) { shadowDistance = glm::max(distance, 1.0f); }
[[nodiscard]] float getShadowDistance() const { return shadowDistance; }
private:
struct PushConstants
{
glm::mat4 transform;
VkDeviceAddress sceneDataBuffer;
VkDeviceAddress vertexBuffer;
std::uint32_t materialId;
std::uint32_t padding;
};
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
std::unique_ptr<Pipeline> m_pipeline;
VkFormat shadowMapFormat{VK_FORMAT_D32_SFLOAT};
ImageID shadowMapId{NULL_IMAGE_ID};
float shadowDistance{25.0f};
// how far in front of / behind the camera (along the light) casters are still captured
float shadowDepthRange{100.0f};
};
#endif //SHADOWMAPPIPELINE_H
@@ -10,6 +10,7 @@
#include <destrum/Graphics/Pipelines/LineRenderingPass.h> #include <destrum/Graphics/Pipelines/LineRenderingPass.h>
#include <destrum/Graphics/Pipelines/MeshPipeline.h> #include <destrum/Graphics/Pipelines/MeshPipeline.h>
#include <destrum/Graphics/Pipelines/QuadRendererPass.h> #include <destrum/Graphics/Pipelines/QuadRendererPass.h>
#include <destrum/Graphics/Pipelines/ShadowMapPipeline.h>
#include <destrum/Graphics/ids.h> #include <destrum/Graphics/ids.h>
#include <destrum/Graphics/MeshDrawCommand.h> #include <destrum/Graphics/MeshDrawCommand.h>
#include <destrum/Graphics/Resources/NBuffer.h> #include <destrum/Graphics/Resources/NBuffer.h>
@@ -17,6 +18,7 @@
#include <memory> #include <memory>
#include <optional>
#include <destrum/Graphics/Pipelines/SkinningPipeline.h> #include <destrum/Graphics/Pipelines/SkinningPipeline.h>
@@ -87,6 +89,16 @@ public:
return renderLightHeatmap; return renderLightHeatmap;
} }
void setShadowDistance(float distance)
{
shadowMapPipeline->setShadowDistance(distance);
}
float getShadowDistance() const
{
return shadowMapPipeline->getShadowDistance();
}
RenderResources* getResources() RenderResources* getResources()
{ {
return resources; return resources;
@@ -138,7 +150,11 @@ private:
std::uint32_t numLights; std::uint32_t numLights;
std::uint32_t tileCountX; std::uint32_t tileCountX;
std::uint32_t debugLightHeatmap; std::uint32_t debugLightHeatmap;
std::uint32_t shadowMapId;
float shadowNormalOffset;
std::uint32_t padding; std::uint32_t padding;
glm::mat4 lightViewProj;
}; };
NBuffer sceneDataBuffer; NBuffer sceneDataBuffer;
@@ -150,6 +166,9 @@ private:
std::unique_ptr<SkinningPipeline> skinningPipeline; std::unique_ptr<SkinningPipeline> skinningPipeline;
std::unique_ptr<LightCullingPipeline> lightCullingPipeline; std::unique_ptr<LightCullingPipeline> lightCullingPipeline;
std::unique_ptr<ShadowMapPipeline> shadowMapPipeline;
std::optional<glm::vec3> shadowLightDirection;
bool renderLightHeatmap{false}; bool renderLightHeatmap{false};
bool initialized{false}; bool initialized{false};
@@ -77,6 +77,8 @@ public:
[[nodiscard]] VkFormat getFormat() const { return m_swapchain.image_format; } [[nodiscard]] VkFormat getFormat() const { return m_swapchain.image_format; }
private: private:
void nameSwapchainObjects(VkDevice device) const;
struct FrameData { struct FrameData {
VkSemaphore swapchainSemaphore{VK_NULL_HANDLE}; VkSemaphore swapchainSemaphore{VK_NULL_HANDLE};
VkFence renderFence{VK_NULL_HANDLE}; VkFence renderFence{VK_NULL_HANDLE};
+61
View File
@@ -1,6 +1,8 @@
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#include <cstdint>
#include <cstdio>
#include <filesystem> #include <filesystem>
#include <optional> #include <optional>
#include <stdexcept> #include <stdexcept>
@@ -87,6 +89,9 @@ namespace vkutil {
VkDeviceSize offset = 0, VkDeviceSize offset = 0,
VkDeviceSize size = VK_WHOLE_SIZE); VkDeviceSize size = VK_WHOLE_SIZE);
// Object names (VK_EXT_debug_utils), shown in RenderDoc, Nsight and validation messages.
// All of these are no-ops when the extension isn't loaded.
void addDebugLabel(VkDevice device, VkObjectType objectType, std::uint64_t objectHandle, const char* label);
void addDebugLabel(VkDevice device, VkImage image, const char* label); void addDebugLabel(VkDevice device, VkImage image, const char* label);
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label); void addDebugLabel(VkDevice device, VkImageView imageView, const char* label);
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label); void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label);
@@ -94,6 +99,62 @@ namespace vkutil {
void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label); void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label);
void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label); void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label);
void addDebugLabel(VkDevice device, VkSampler sampler, const char* label); void addDebugLabel(VkDevice device, VkSampler sampler, const char* label);
void addDebugLabel(VkDevice device, VkDescriptorPool descriptorPool, const char* label);
void addDebugLabel(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* label);
void addDebugLabel(VkDevice device, VkDescriptorSet descriptorSet, const char* label);
void addDebugLabel(VkDevice device, VkCommandPool commandPool, const char* label);
void addDebugLabel(VkDevice device, VkCommandBuffer commandBuffer, const char* label);
void addDebugLabel(VkDevice device, VkFence fence, const char* label);
void addDebugLabel(VkDevice device, VkSemaphore semaphore, const char* label);
void addDebugLabel(VkDevice device, VkQueue queue, const char* label);
// Command buffer regions, they nest like a stack: every begin needs a matching end
// in the same command buffer.
[[nodiscard]] bool debugLabelsEnabled();
void cmdBeginLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
void cmdEndLabel(VkCommandBuffer cmd);
void cmdInsertLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
// printf style, only formats when labels are actually recorded (cheap enough for per draw labels)
template <typename... Args>
void cmdBeginLabelFormatted(VkCommandBuffer cmd, const glm::vec4& color, const char* format, Args... args)
{
if (!debugLabelsEnabled()) {
return;
}
char label[256];
std::snprintf(label, sizeof(label), format, args...);
cmdBeginLabel(cmd, label, color);
}
class ScopedCmdLabel {
public:
ScopedCmdLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
~ScopedCmdLabel();
ScopedCmdLabel(const ScopedCmdLabel& other) = delete;
ScopedCmdLabel(ScopedCmdLabel&& other) noexcept = delete;
ScopedCmdLabel& operator=(const ScopedCmdLabel& other) = delete;
ScopedCmdLabel& operator=(ScopedCmdLabel&& other) noexcept = delete;
private:
VkCommandBuffer cmd{VK_NULL_HANDLE};
};
// Colors used for the renderer's labels, so passes are easy to tell apart in a capture
namespace labelColors {
inline const glm::vec4 frame{0.8f, 0.8f, 0.8f, 1.0f};
inline const glm::vec4 compute{0.9f, 0.5f, 0.1f, 1.0f};
inline const glm::vec4 shadow{0.3f, 0.3f, 0.6f, 1.0f};
inline const glm::vec4 depth{0.4f, 0.4f, 0.4f, 1.0f};
inline const glm::vec4 opaque{0.2f, 0.7f, 0.3f, 1.0f};
inline const glm::vec4 sky{0.3f, 0.6f, 0.9f, 1.0f};
inline const glm::vec4 debug{0.9f, 0.2f, 0.6f, 1.0f};
inline const glm::vec4 ui{0.9f, 0.9f, 0.2f, 1.0f};
inline const glm::vec4 transfer{0.6f, 0.4f, 0.2f, 1.0f};
inline const glm::vec4 draw{0.5f, 0.8f, 0.5f, 1.0f};
}
struct RenderingInfoParams { struct RenderingInfoParams {
VkExtent2D renderExtent; VkExtent2D renderExtent;
+10 -1
View File
@@ -47,6 +47,7 @@ void LightComponent::Render(const RenderContext& ctx)
.range = m_Range, .range = m_Range,
.innerConeAngle = m_InnerConeAngle, .innerConeAngle = m_InnerConeAngle,
.outerConeAngle = m_OuterConeAngle, .outerConeAngle = m_OuterConeAngle,
.castShadows = m_CastShadows,
}); });
} }
@@ -57,7 +58,8 @@ nlohmann::json LightComponent::Serialize() const {
{"intensity", m_Intensity}, {"intensity", m_Intensity},
{"range", m_Range}, {"range", m_Range},
{"innerConeAngle", m_InnerConeAngle}, {"innerConeAngle", m_InnerConeAngle},
{"outerConeAngle", m_OuterConeAngle} {"outerConeAngle", m_OuterConeAngle},
{"castShadows", m_CastShadows}
}; };
} }
@@ -88,6 +90,10 @@ void LightComponent::Deserialize(const nlohmann::json& data) {
outerConeAngle = data.at("outerConeAngle").get<float>(); outerConeAngle = data.at("outerConeAngle").get<float>();
} }
SetConeAngles(innerConeAngle, outerConeAngle); SetConeAngles(innerConeAngle, outerConeAngle);
if (data.contains("castShadows")) {
m_CastShadows = data.at("castShadows").get<bool>();
}
} }
void LightComponent::ImGuiInspector() { void LightComponent::ImGuiInspector() {
@@ -106,6 +112,9 @@ void LightComponent::ImGuiInspector() {
} }
if (m_Type == LightType::Directional) { if (m_Type == LightType::Directional) {
ImGui::Checkbox("Cast Shadows", &m_CastShadows);
ImGui::SameLine();
ImGui::TextDisabled("(first directional light only)");
return; return;
} }
@@ -33,6 +33,9 @@ void MeshRendererComponent::Start() {
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
); );
const std::string bufferName = GetGameObject()->GetName() + " (skinned vertices)";
vkutil::addDebugLabel(gfxDevice.getDevice(), m_skinnedMesh->skinnedVertexBuffer.buffer, bufferName.c_str());
} }
} }
@@ -74,6 +74,7 @@ void BindlessSetManager::init(
}; };
VK_CHECK(vkCreateDescriptorPool(device, &poolInfo, nullptr, &descPool)); VK_CHECK(vkCreateDescriptorPool(device, &poolInfo, nullptr, &descPool));
vkutil::addDebugLabel(device, descPool, "bindless descriptor pool");
} }
{ // build desc set layout { // build desc set layout
@@ -111,6 +112,7 @@ void BindlessSetManager::init(
}; };
VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &descSetLayout)); VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &descSetLayout));
vkutil::addDebugLabel(device, descSetLayout, "bindless descriptor set layout");
} }
{ // alloc desc set { // alloc desc set
@@ -122,6 +124,7 @@ void BindlessSetManager::init(
}; };
VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &descSet)); VK_CHECK(vkAllocateDescriptorSets(device, &allocInfo, &descSet));
vkutil::addDebugLabel(device, descSet, "bindless descriptor set");
} }
initDefaultSamplers(device, maxAnisotropy); initDefaultSamplers(device, maxAnisotropy);
+6 -1
View File
@@ -99,8 +99,13 @@ void ComputePipeline::CreateComputePipeline(const std::string& compPath,
throw std::runtime_error("Can't make compute pipeline!"); throw std::runtime_error("Can't make compute pipeline!");
} }
vkutil::addDebugLabel(m_device.getDevice(), m_compShaderModule, compFileName.c_str());
if (!configInfo.name.empty()) { if (!configInfo.name.empty()) {
vkutil::addDebugLabel(GameState::GetInstance().Gfx().getDevice(), m_computePipeline, configInfo.name.c_str()); vkutil::addDebugLabel(m_device.getDevice(), m_computePipeline, configInfo.name.c_str());
const std::string layoutName = configInfo.name + " Layout";
vkutil::addDebugLabel(m_device.getDevice(), configInfo.pipelineLayout, layoutName.c_str());
} }
} }
+4
View File
@@ -156,6 +156,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; { auto swapchainLayout = VK_IMAGE_LAYOUT_UNDEFINED; {
ZoneScopedN("Clear Swapchain Image"); ZoneScopedN("Clear Swapchain Image");
vkutil::ScopedCmdLabel label(cmd, "Clear Swapchain Image", vkutil::labelColors::transfer);
const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT); const VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL); vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_GENERAL);
@@ -167,6 +168,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
if (true) { if (true) {
ZoneScopedN("Copy DrawImage To Swapchain"); ZoneScopedN("Copy DrawImage To Swapchain");
vkutil::ScopedCmdLabel label(cmd, "Copy DrawImage To Swapchain", vkutil::labelColors::transfer);
vkutil::transitionImage( vkutil::transitionImage(
cmd, cmd,
@@ -190,6 +192,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
if (props.imguiPass) { if (props.imguiPass) {
ZoneScopedN("ImGui Render"); ZoneScopedN("ImGui Render");
vkutil::ScopedCmdLabel label(cmd, "ImGui Render", vkutil::labelColors::ui);
props.imguiPass->render( props.imguiPass->render(
cmd, cmd,
@@ -202,6 +205,7 @@ void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const E
{ {
ZoneScopedN("Transition Swapchain To Present"); ZoneScopedN("Transition Swapchain To Present");
vkutil::ScopedCmdLabel label(cmd, "Transition Swapchain To Present", vkutil::labelColors::transfer);
vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); vkutil::transitionImage(cmd, swapchainImage, swapchainLayout, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; swapchainLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
@@ -40,6 +40,10 @@ void VulkanImmediateExecutor::init(
}; };
VK_CHECK(vkCreateFence(deviceHandle, &fenceCreateInfo, nullptr, &immFence)); VK_CHECK(vkCreateFence(deviceHandle, &fenceCreateInfo, nullptr, &immFence));
vkutil::addDebugLabel(deviceHandle, immCommandPool, "immediate command pool");
vkutil::addDebugLabel(deviceHandle, immCommandBuffer, "immediate command buffer");
vkutil::addDebugLabel(deviceHandle, immFence, "immediate fence");
initialized = true; initialized = true;
} catch (...) { } catch (...) {
cleanup(deviceHandle); cleanup(deviceHandle);
@@ -26,6 +26,11 @@ void FrameManager::init(VkDevice dev, std::uint32_t queueFamily) {
const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1); const auto cmdAllocInfo = vkinit::commandBufferAllocateInfo(commandPool, 1);
auto& mainCommandBuffer = frames[i].commandBuffer; auto& mainCommandBuffer = frames[i].commandBuffer;
VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer)); VK_CHECK(vkAllocateCommandBuffers(device, &cmdAllocInfo, &mainCommandBuffer));
const std::string poolName = "frame " + std::to_string(i) + " command pool";
const std::string cmdName = "frame " + std::to_string(i) + " command buffer";
vkutil::addDebugLabel(device, commandPool, poolName.c_str());
vkutil::addDebugLabel(device, mainCommandBuffer, cmdName.c_str());
} }
} catch (...) { } catch (...) {
cleanup(dev); cleanup(dev);
@@ -178,7 +178,9 @@ std::optional<GPUImage> ImageManager::loadImageFromFile(
} }
image.debugName = path.string(); image.debugName = path.string();
vkutil::addDebugLabel(device, image.image, path.string().c_str()); vkutil::addDebugLabel(device, image.image, image.debugName.c_str());
const std::string viewName = image.debugName + " (view)";
vkutil::addDebugLabel(device, image.imageView, viewName.c_str());
return image; return image;
} }
+3
View File
@@ -156,6 +156,9 @@ void MeshCache::uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE); VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE);
const auto skinningBufferName = cpuMesh.name + " (skinning data)";
vkutil::addDebugLabel(gfxDevice.getDevice(), gpuMesh.skinningDataBuffer.buffer, skinningBufferName.c_str());
auto skinningStaging = auto skinningStaging =
gfxDevice.createBuffer( gfxDevice.createBuffer(
skinningDataSize, skinningDataSize,
+17 -18
View File
@@ -146,11 +146,11 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
CreateShaderModule(vertCode, &m_vertShaderModule); CreateShaderModule(vertCode, &m_vertShaderModule);
// vkutil::addDebugLabel( vkutil::addDebugLabel(
// m_device.getDevice(), m_device.getDevice(),
// m_fragShaderModule, m_vertShaderModule,
// VertFileName.c_str() VertFileName.c_str()
// ); );
VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@@ -173,11 +173,11 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
CreateShaderModule(fragCode, &m_fragShaderModule); CreateShaderModule(fragCode, &m_fragShaderModule);
// vkutil::addDebugLabel( vkutil::addDebugLabel(
// m_device.getDevice(), m_device.getDevice(),
// m_fragShaderModule, m_fragShaderModule,
// FragFileName.c_str() FragFileName.c_str()
// ); );
VkPipelineShaderStageCreateInfo fragShaderStageInfo{}; VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
@@ -231,18 +231,17 @@ void Pipeline::CreateGraphicsPipeline(const std::string& vertPath, const std::st
pipelineInfo.basePipelineIndex = -1; pipelineInfo.basePipelineIndex = -1;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
if (!configInfo.name.empty()) {
// DebugLabel::SetObjectName(
// reinterpret_cast<uint64_t>(pipelineInfo.layout),
// VK_OBJECT_TYPE_PIPELINE_LAYOUT,
// configInfo.name.c_str()
// );
}
if (vkCreateGraphicsPipelines(m_device.getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) { if (vkCreateGraphicsPipelines(m_device.getDevice(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("Can't make pipeline!"); throw std::runtime_error("Can't make pipeline!");
} }
if (!configInfo.name.empty()) {
vkutil::addDebugLabel(m_device.getDevice(), m_graphicsPipeline, configInfo.name.c_str());
const std::string layoutName = configInfo.name + " Layout";
vkutil::addDebugLabel(m_device.getDevice(), configInfo.pipelineLayout, layoutName.c_str());
}
} }
void Pipeline::CreateShaderModule(const std::vector<char>& code, VkShaderModule* shaderModule) const { void Pipeline::CreateShaderModule(const std::vector<char>& code, VkShaderModule* shaderModule) const {
@@ -158,7 +158,8 @@ void LightCullingPipeline::appendLight(const Light& light)
.type = static_cast<std::uint32_t>(light.type), .type = static_cast<std::uint32_t>(light.type),
.spotInnerCos = std::cos(light.innerConeAngle), .spotInnerCos = std::cos(light.innerConeAngle),
.spotOuterCos = std::cos(light.outerConeAngle), .spotOuterCos = std::cos(light.outerConeAngle),
.padding = glm::vec2{0.0f}, .castShadows = light.castShadows ? 1u : 0u,
.padding = 0.0f,
}; };
lightsBuffer.append(gpuLight); lightsBuffer.append(gpuLight);
} }
@@ -9,6 +9,7 @@
#include <destrum/Graphics/RenderResources.h> #include <destrum/Graphics/RenderResources.h>
#include <destrum/Graphics/Caches/MeshCache.h> #include <destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Frustum.h> #include <destrum/Graphics/Frustum.h>
#include <destrum/Graphics/Util.h>
#include "volk.h" #include "volk.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
@@ -219,6 +220,16 @@ void MeshPipeline::drawMeshes(
const auto& mesh = meshCache.getMesh(dc.meshId); const auto& mesh = meshCache.getMesh(dc.meshId);
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
vkutil::cmdBeginLabelFormatted(
cmd,
vkutil::labelColors::draw,
"%s [mesh %zu, material %u%s]",
meshKey.empty() ? "Mesh" : meshKey.c_str(),
dc.meshId,
dc.materialId,
dc.skinnedMesh != nullptr ? ", skinned" : "");
if (dc.meshId != prevMeshId) if (dc.meshId != prevMeshId)
{ {
prevMeshId = dc.meshId; prevMeshId = dc.meshId;
@@ -254,6 +265,8 @@ void MeshPipeline::drawMeshes(
); );
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0); vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
vkutil::cmdEndLabel(cmd);
}; };
if (!sortedDrawCommands.empty()) if (!sortedDrawCommands.empty())
@@ -42,12 +42,14 @@ void QuadRendererPass::init(GfxDevice& gfxDevice, RenderResources& resources, Vk
vertexBytes, vertexBytes,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST); VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), vertexBuffer.buffer, "quad vertices");
const std::size_t indexBytes = InitialQuadCapacity * IndicesPerQuad * sizeof(std::uint32_t); const std::size_t indexBytes = InitialQuadCapacity * IndicesPerQuad * sizeof(std::uint32_t);
indexBuffer = gfxDevice.createBuffer( indexBuffer = gfxDevice.createBuffer(
indexBytes, indexBytes,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST); VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), indexBuffer.buffer, "quad indices");
quadCapacity = InitialQuadCapacity; quadCapacity = InitialQuadCapacity;
@@ -321,6 +323,7 @@ void QuadRendererPass::ensureCapacity(
newCapacity * VerticesPerQuad * sizeof(QuadVertex), newCapacity * VerticesPerQuad * sizeof(QuadVertex),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST); VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), vertexBuffer.buffer, "quad vertices");
if (indexBuffer.buffer != VK_NULL_HANDLE) { if (indexBuffer.buffer != VK_NULL_HANDLE) {
gfxDevice.destroyBuffer(indexBuffer); gfxDevice.destroyBuffer(indexBuffer);
@@ -329,6 +332,7 @@ void QuadRendererPass::ensureCapacity(
newCapacity * IndicesPerQuad * sizeof(std::uint32_t), newCapacity * IndicesPerQuad * sizeof(std::uint32_t),
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST); VMA_MEMORY_USAGE_AUTO_PREFER_HOST);
vkutil::addDebugLabel(gfxDevice.getDevice(), indexBuffer.buffer, "quad indices");
quadCapacity = newCapacity; quadCapacity = newCapacity;
} }
@@ -0,0 +1,265 @@
#include <destrum/Graphics/Pipelines/ShadowMapPipeline.h>
#include <array>
#include <cassert>
#include <cmath>
#include <stdexcept>
#include <glm/gtc/matrix_transform.hpp>
#include <destrum/FS/AssetFS.h>
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/RenderResources.h>
#include <destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Util.h>
#include "volk.h"
#include "spdlog/spdlog.h"
void ShadowMapPipeline::init(GfxDevice& gfxDevice, RenderResources& resources)
{
try
{
const auto vertexShader =
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/shadow.vert");
const auto bufferRange = VkPushConstantRange{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.offset = 0,
.size = sizeof(PushConstants),
};
const auto pushConstantRanges = std::array{bufferRange};
const auto layouts = std::array{
resources.getBindlessDescSetLayout()
};
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = static_cast<std::uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount = static_cast<std::uint32_t>(pushConstantRanges.size());
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
if (vkCreatePipelineLayout(
gfxDevice.getDevice(),
&pipelineLayoutInfo,
nullptr,
&m_pipelineLayout) != VK_SUCCESS)
{
throw std::runtime_error("Could not create shadow map pipeline layout");
}
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "Shadow Map Pipeline";
pipelineConfig.pipelineLayout = m_pipelineLayout;
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.colorAttachments = {};
pipelineConfig.colorBlendInfo.attachmentCount = 0;
pipelineConfig.depthAttachment = shadowMapFormat;
// the light projection isn't Y flipped like the camera's, so the winding is mirrored
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
pipelineConfig.rasterizationInfo.depthBiasEnable = VK_TRUE;
pipelineConfig.rasterizationInfo.depthBiasConstantFactor = 0.0f;
pipelineConfig.rasterizationInfo.depthBiasSlopeFactor = 2.0f;
m_pipeline = std::make_unique<Pipeline>(
gfxDevice,
vertexShader.string(),
"",
pipelineConfig
);
const auto createInfo = vkutil::CreateImageInfo{
.format = shadowMapFormat,
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.extent = VkExtent3D{SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1},
};
shadowMapId = resources.createImage(gfxDevice, createInfo, "shadow map", nullptr, shadowMapId);
spdlog::info("Created {0}x{0} shadow map with id {1}", SHADOW_MAP_SIZE, shadowMapId);
}
catch (...)
{
cleanup(gfxDevice.getDevice());
throw;
}
}
void ShadowMapPipeline::cleanup(VkDevice device)
{
m_pipeline.reset();
if (m_pipelineLayout != VK_NULL_HANDLE && device != VK_NULL_HANDLE)
{
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
}
m_pipelineLayout = VK_NULL_HANDLE;
shadowMapId = NULL_IMAGE_ID;
}
glm::mat4 ShadowMapPipeline::calculateLightViewProj(const glm::vec3& lightDirection, const glm::vec3& center) const
{
const glm::vec3 direction = glm::normalize(lightDirection);
const glm::vec3 up = std::abs(direction.y) > 0.99f ? glm::vec3{0.0f, 0.0f, 1.0f} : glm::vec3{0.0f, 1.0f, 0.0f};
const glm::mat4 lightView = glm::lookAt(glm::vec3{0.0f}, direction, up);
const float texelSize = (2.0f * shadowDistance) / static_cast<float>(SHADOW_MAP_SIZE);
glm::vec3 lightSpaceCenter = glm::vec3(lightView * glm::vec4(center, 1.0f));
lightSpaceCenter.x = std::floor(lightSpaceCenter.x / texelSize) * texelSize;
lightSpaceCenter.y = std::floor(lightSpaceCenter.y / texelSize) * texelSize;
const glm::mat4 lightProj = glm::orthoRH_ZO(
lightSpaceCenter.x - shadowDistance,
lightSpaceCenter.x + shadowDistance,
lightSpaceCenter.y - shadowDistance,
lightSpaceCenter.y + shadowDistance,
-lightSpaceCenter.z - shadowDepthRange,
-lightSpaceCenter.z + shadowDepthRange);
return lightProj * lightView;
}
float ShadowMapPipeline::getNormalOffset() const
{
const float texelSize = (2.0f * shadowDistance) / static_cast<float>(SHADOW_MAP_SIZE);
return texelSize * 1.5f;
}
void ShadowMapPipeline::draw(
VkCommandBuffer cmd,
const RenderResources& resources,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
{
if (!m_pipeline || shadowMapId == NULL_IMAGE_ID)
{
return;
}
const auto& shadowMap = resources.getImage(shadowMapId);
vkutil::transitionImage(
cmd,
shadowMap.image,
shadowMap.layout,
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
shadowMap.setLayout(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
auto renderInfo = vkutil::createRenderingInfo({
.renderExtent = shadowMap.getExtent2D(),
.depthImageView = shadowMap.imageView,
.depthImageClearValue = 1.f,
});
renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment;
vkCmdBeginRendering(cmd, &renderInfo.renderingInfo);
m_pipeline->bind(cmd);
resources.bindBindlessDescSet(cmd, m_pipelineLayout);
const auto viewport = VkViewport{
.x = 0.f,
.y = 0.f,
.width = static_cast<float>(SHADOW_MAP_SIZE),
.height = static_cast<float>(SHADOW_MAP_SIZE),
.minDepth = 0.f,
.maxDepth = 1.f,
};
vkCmdSetViewport(cmd, 0, 1, &viewport);
const auto scissor = VkRect2D{
.offset = {},
.extent = shadowMap.getExtent2D(),
};
vkCmdSetScissor(cmd, 0, 1, &scissor);
vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL);
const MeshCache& meshCache = resources.meshes();
MeshID prevMeshId = NULL_MESH_ID;
const auto drawOne = [&](const MeshDrawCommand& dc)
{
if (!dc.castShadow)
{
return;
}
const auto& mesh = meshCache.getMesh(dc.meshId);
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
vkutil::cmdBeginLabelFormatted(
cmd,
vkutil::labelColors::draw,
"%s [mesh %zu, material %u%s]",
meshKey.empty() ? "Mesh" : meshKey.c_str(),
dc.meshId,
dc.materialId,
dc.skinnedMesh != nullptr ? ", skinned" : "");
if (dc.meshId != prevMeshId)
{
prevMeshId = dc.meshId;
vkCmdBindIndexBuffer(cmd, mesh.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
}
const auto pushConstants = PushConstants{
.transform = dc.transformMatrix,
.sceneDataBuffer = sceneDataBuffer.address,
.vertexBuffer =
dc.skinnedMesh != nullptr
? dc.skinnedMesh->skinnedVertexBuffer.address
: mesh.vertexBuffer.address,
.materialId = dc.materialId,
.padding = 0,
};
vkCmdPushConstants(
cmd,
m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT,
0,
sizeof(PushConstants),
&pushConstants);
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
vkutil::cmdEndLabel(cmd);
};
if (!sortedDrawCommands.empty())
{
for (std::size_t drawIndex : sortedDrawCommands)
{
assert(drawIndex < drawCommands.size());
drawOne(drawCommands[drawIndex]);
}
}
else
{
for (const MeshDrawCommand& dc : drawCommands)
{
drawOne(dc);
}
}
vkCmdEndRendering(cmd);
vkutil::transitionImage(
cmd,
shadowMap.image,
shadowMap.layout,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
shadowMap.setLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
@@ -53,6 +53,9 @@ void SkinningPipeline::init(GfxDevice& gfxDevice) {
MAX_JOINT_MATRICES * sizeof(glm::mat4), MAX_JOINT_MATRICES * sizeof(glm::mat4),
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VMA_MEMORY_USAGE_CPU_TO_GPU); VMA_MEMORY_USAGE_CPU_TO_GPU);
const std::string bufferName = "joint matrices (frame " + std::to_string(i) + ")";
vkutil::addDebugLabel(device, jointMatricesBuffer.buffer.buffer, bufferName.c_str());
} }
} catch (...) { } catch (...) {
cleanup(gfxDevice); cleanup(gfxDevice);
@@ -84,6 +87,9 @@ void SkinningPipeline::doSkinning(VkCommandBuffer cmd,
assert(mesh.hasSkeleton); assert(mesh.hasSkeleton);
assert(dc.skinnedMesh); assert(dc.skinnedMesh);
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
vkutil::ScopedCmdLabel label(cmd, meshKey.empty() ? "Skin Mesh" : meshKey.c_str(), vkutil::labelColors::compute);
const auto cs = PushConstants{ const auto cs = PushConstants{
.jointMatricesBuffer = getCurrentFrameData(frameIndex).jointMatricesBuffer.buffer.address, .jointMatricesBuffer = getCurrentFrameData(frameIndex).jointMatricesBuffer.buffer.address,
.jointMatricesStartIndex = static_cast<std::uint32_t>(dc.jointMatricesStartIndex), .jointMatricesStartIndex = static_cast<std::uint32_t>(dc.jointMatricesStartIndex),
+2
View File
@@ -130,6 +130,8 @@ ImageID RenderResources::createImage(
if (!debugName.empty()) { if (!debugName.empty()) {
vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.image, debugName.c_str()); vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.image, debugName.c_str());
const std::string viewName = debugName + " (view)";
vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.imageView, viewName.c_str());
image.debugName = debugName; image.debugName = debugName;
} }
+58 -2
View File
@@ -44,6 +44,9 @@ void GameRenderer::init(GfxDevice& gfxDevice, RenderResources& _resources, glm::
lightCullingPipeline = std::make_unique<LightCullingPipeline>(); lightCullingPipeline = std::make_unique<LightCullingPipeline>();
lightCullingPipeline->init(gfxDevice, _resources, drawImageSize); lightCullingPipeline->init(gfxDevice, _resources, drawImageSize);
shadowMapPipeline = std::make_unique<ShadowMapPipeline>();
shadowMapPipeline->init(gfxDevice, _resources);
lineRenderingPass = std::make_unique<LineRenderingPass>(); lineRenderingPass = std::make_unique<LineRenderingPass>();
lineRenderingPass->init(gfxDevice, drawImageFormat); lineRenderingPass->init(gfxDevice, drawImageFormat);
@@ -66,6 +69,7 @@ void GameRenderer::beginDrawing(GfxDevice& gfxDevice)
meshDrawCommands.clear(); meshDrawCommands.clear();
skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex()); skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
lightCullingPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex()); lightCullingPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
shadowLightDirection.reset();
QuadRenderingManager::GetInstance().ClearQuads(); QuadRenderingManager::GetInstance().ClearQuads();
} }
@@ -97,9 +101,11 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
ZoneScopedN("GameRenderer::draw"); ZoneScopedN("GameRenderer::draw");
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw");
vkutil::ScopedCmdLabel frameLabel(cmd, "GameRenderer::draw", vkutil::labelColors::frame);
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning");
vkutil::ScopedCmdLabel label(cmd, "Skinning", vkutil::labelColors::compute);
skinningPipeline->flushCurrentFrame( skinningPipeline->flushCurrentFrame(
cmd, cmd,
@@ -118,10 +124,17 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Lights Buffer Flush"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Lights Buffer Flush");
vkutil::ScopedCmdLabel label(cmd, "Lights Buffer Flush", vkutil::labelColors::transfer);
lightCullingPipeline->flushCurrentFrame(cmd, gfxDevice); lightCullingPipeline->flushCurrentFrame(cmd, gfxDevice);
} }
const glm::mat4 lightViewProj = shadowLightDirection
? shadowMapPipeline->calculateLightViewProj(
*shadowLightDirection,
sceneData.camera.GetPosition())
: glm::mat4{1.0f};
// TODO: there has to be a better way to do this // TODO: there has to be a better way to do this
const auto gpuSceneData = GPUSceneData{ const auto gpuSceneData = GPUSceneData{
.view = sceneData.camera.GetViewMatrix(), .view = sceneData.camera.GetViewMatrix(),
@@ -139,11 +152,15 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
.numLights = lightCullingPipeline->getNumLights(), .numLights = lightCullingPipeline->getNumLights(),
.tileCountX = lightCullingPipeline->getTileCount().x, .tileCountX = lightCullingPipeline->getTileCount().x,
.debugLightHeatmap = renderLightHeatmap ? 1u : 0u, .debugLightHeatmap = renderLightHeatmap ? 1u : 0u,
.shadowMapId = static_cast<std::uint32_t>(shadowMapPipeline->getShadowMapId()),
.shadowNormalOffset = shadowMapPipeline->getNormalOffset(),
.padding = 0, .padding = 0,
.lightViewProj = lightViewProj,
}; };
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier");
vkutil::ScopedCmdLabel label(cmd, "Material Buffer Barrier", vkutil::labelColors::transfer);
vkutil::bufferHostWriteToShaderReadBarrier( vkutil::bufferHostWriteToShaderReadBarrier(
cmd, cmd,
@@ -155,6 +172,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Upload Scene Data"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Upload Scene Data");
vkutil::ScopedCmdLabel label(cmd, "Upload Scene Data", vkutil::labelColors::transfer);
sceneDataBuffer.uploadNewData( sceneDataBuffer.uploadNewData(
cmd, cmd,
@@ -189,8 +207,22 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
depthImage.setLayout(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); depthImage.setLayout(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
} }
if (shadowLightDirection)
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Shadow Map");
vkutil::ScopedCmdLabel label(cmd, "Shadow Map", vkutil::labelColors::shadow);
shadowMapPipeline->draw(
cmd,
*resources,
sceneDataBuffer.getBuffer(),
meshDrawCommands,
sortedMeshDrawCommands);
}
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Depth Prepass"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Depth Prepass");
vkutil::ScopedCmdLabel label(cmd, "Depth Prepass", vkutil::labelColors::depth);
auto depthPrepassInfo = vkutil::createRenderingInfo({ auto depthPrepassInfo = vkutil::createRenderingInfo({
.renderExtent = drawImage.getExtent2D(), .renderExtent = drawImage.getExtent2D(),
@@ -215,6 +247,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Light Culling"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Light Culling");
vkutil::ScopedCmdLabel label(cmd, "Light Culling", vkutil::labelColors::compute);
vkutil::transitionImage( vkutil::transitionImage(
cmd, cmd,
@@ -247,6 +280,8 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
renderInfo.renderingInfo.pColorAttachments = &renderInfo.colorAttachment; renderInfo.renderingInfo.pColorAttachments = &renderInfo.colorAttachment;
renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment; renderInfo.renderingInfo.pDepthAttachment = &renderInfo.depthAttachment;
vkutil::cmdBeginLabel(cmd, "Forward Pass", vkutil::labelColors::opaque);
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdBeginRendering"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "vkCmdBeginRendering");
@@ -255,6 +290,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "MeshPipeline::draw");
vkutil::ScopedCmdLabel label(cmd, "MeshPipeline::draw", vkutil::labelColors::opaque);
meshPipeline->draw( meshPipeline->draw(
cmd, cmd,
@@ -268,6 +304,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw");
vkutil::ScopedCmdLabel label(cmd, "SkyboxPipeline::draw", vkutil::labelColors::sky);
skyboxPipeline->draw(cmd, *resources, camera); skyboxPipeline->draw(cmd, *resources, camera);
} }
@@ -278,8 +315,11 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
vkCmdEndRendering(cmd); vkCmdEndRendering(cmd);
} }
vkutil::cmdEndLabel(cmd);
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "LineRenderingPass::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "LineRenderingPass::draw");
vkutil::ScopedCmdLabel label(cmd, "LineRenderingPass::draw", vkutil::labelColors::debug);
lineRenderingPass->draw( lineRenderingPass->draw(
cmd, cmd,
@@ -291,6 +331,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "QuadRendererPass::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "QuadRendererPass::draw");
vkutil::ScopedCmdLabel label(cmd, "QuadRendererPass::draw", vkutil::labelColors::ui);
quadRendererPass->draw( quadRendererPass->draw(
cmd, cmd,
@@ -302,7 +343,6 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
static_cast<float>(drawImage.extent.height), static_cast<float>(drawImage.extent.height),
0.0f, -1.0f, 1.0f)); 0.0f, -1.0f, 1.0f));
} }
// vkutil::cmdEndLabel(cmd);
} }
void GameRenderer::drawQuads( void GameRenderer::drawQuads(
@@ -335,6 +375,9 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
if (lightCullingPipeline) if (lightCullingPipeline)
lightCullingPipeline->cleanup(gfxDevice); lightCullingPipeline->cleanup(gfxDevice);
if (shadowMapPipeline)
shadowMapPipeline->cleanup(device);
if (skyboxPipeline) if (skyboxPipeline)
skyboxPipeline->cleanup(device); skyboxPipeline->cleanup(device);
@@ -358,6 +401,8 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
lineRenderingPass.reset(); lineRenderingPass.reset();
quadRendererPass.reset(); quadRendererPass.reset();
lightCullingPipeline.reset(); lightCullingPipeline.reset();
shadowMapPipeline.reset();
shadowLightDirection.reset();
pendingMaterialUploads.clear(); pendingMaterialUploads.clear();
meshDrawCommands.clear(); meshDrawCommands.clear();
sortedMeshDrawCommands.clear(); sortedMeshDrawCommands.clear();
@@ -402,7 +447,18 @@ void GameRenderer::drawSkinnedMesh(MeshID id,
void GameRenderer::submitLight(const Light& light) void GameRenderer::submitLight(const Light& light)
{ {
lightCullingPipeline->appendLight(light); Light submittedLight = light;
// there's a single shadow map, the first shadow casting directional light gets it
submittedLight.castShadows =
light.castShadows && light.type == LightType::Directional && !shadowLightDirection;
if (submittedLight.castShadows)
{
shadowLightDirection = light.direction;
}
lightCullingPipeline->appendLight(submittedLight);
} }
const GPUImage& GameRenderer::getDrawImage() const const GPUImage& GameRenderer::getDrawImage() const
@@ -71,6 +71,8 @@ void CubeMap::RenderToCubemap(
} }
gfxDevice.getImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) { gfxDevice.getImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
vkutil::ScopedCmdLabel label(cmd, "HDRI To Cubemap", vkutil::labelColors::sky);
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -108,6 +110,8 @@ void CubeMap::RenderToCubemap(
scissor.extent = {size, size}; scissor.extent = {size, size};
for (std::uint32_t face = 0; face < 6; ++face) { for (std::uint32_t face = 0; face < 6; ++face) {
vkutil::cmdBeginLabelFormatted(cmd, vkutil::labelColors::draw, "Cubemap Face %u", face);
PC pc{}; PC pc{};
pc.viewMtx = viewMatrices[face]; pc.viewMtx = viewMatrices[face];
pc.projMtx = m_projection; pc.projMtx = m_projection;
@@ -153,6 +157,8 @@ void CubeMap::RenderToCubemap(
vkCmdDraw(cmd, 36, 1, 0, 0); vkCmdDraw(cmd, 36, 1, 0, 0);
vkCmdEndRendering(cmd); vkCmdEndRendering(cmd);
vkutil::cmdEndLabel(cmd);
} }
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -199,6 +205,7 @@ void CubeMap::CreateCubeMap(
.mipMap = false, .mipMap = false,
.isCubemap = true .isCubemap = true
}); });
vkutil::addDebugLabel(gfxDevice.getDevice(), cubeMapImage.image, "skybox cubemap");
std::array<VkImageView, 6> faceViews{}; std::array<VkImageView, 6> faceViews{};
@@ -220,6 +227,9 @@ void CubeMap::CreateCubeMap(
&viewInfo, &viewInfo,
nullptr, nullptr,
&faceViews[face])); &faceViews[face]));
const std::string faceViewName = "skybox cubemap face " + std::to_string(face) + " (view)";
vkutil::addDebugLabel(gfxDevice.getDevice(), faceViews[face], faceViewName.c_str());
} }
spdlog::info("HDRI image id = {}", m_hdrImage); spdlog::info("HDRI image id = {}", m_hdrImage);
@@ -305,6 +315,7 @@ void CubeMap::InitCubemapPipeline(
PipelineConfigInfo pipelineConfig{}; PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig); Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "HDRI To Cubemap Pipeline";
pipelineConfig.vertexAttributeDescriptions = {}; pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {}; pipelineConfig.vertexBindingDescriptions = {};
+20
View File
@@ -21,6 +21,22 @@ void Swapchain::initSync(VkDevice device) {
for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) { for (std::uint32_t i = 0; i < FRAMES_IN_FLIGHT; ++i) {
VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &frames[i].renderFence)); VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &frames[i].renderFence));
VK_CHECK(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &frames[i].swapchainSemaphore)); VK_CHECK(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &frames[i].swapchainSemaphore));
const auto fenceName = std::format("frame {} render fence", i);
const auto semaphoreName = std::format("frame {} swapchain semaphore", i);
vkutil::addDebugLabel(device, frames[i].renderFence, fenceName.c_str());
vkutil::addDebugLabel(device, frames[i].swapchainSemaphore, semaphoreName.c_str());
}
}
void Swapchain::nameSwapchainObjects(VkDevice device) const {
for (std::size_t i = 0; i < images.size(); ++i) {
const auto imageName = std::format("swapchain image {}", i);
const auto viewName = std::format("swapchain image {} (view)", i);
const auto semaphoreName = std::format("swapchain image {} render semaphore", i);
vkutil::addDebugLabel(device, images[i], imageName.c_str());
vkutil::addDebugLabel(device, imageViews[i], viewName.c_str());
vkutil::addDebugLabel(device, imageRenderSemaphores[i], semaphoreName.c_str());
} }
} }
@@ -85,6 +101,8 @@ void Swapchain::createSwapchain(
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem)); VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
} }
nameSwapchainObjects(vkbDevice);
extent = m_swapchain.extent; extent = m_swapchain.extent;
dirty = false; dirty = false;
} }
@@ -187,6 +205,8 @@ void Swapchain::recreateSwapchain(
VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem)); VK_CHECK(vkCreateSemaphore(vkbDevice, &sci, nullptr, &sem));
} }
nameSwapchainObjects(vkbDevice);
extent = m_swapchain.extent; extent = m_swapchain.extent;
dirty = false; dirty = false;
} }
+101 -101
View File
@@ -188,54 +188,124 @@ void vkutil::bufferHostWriteToTransferReadBarrier(
} }
void vkutil::addDebugLabel(VkDevice device, VkImage image, const char* label) { void vkutil::addDebugLabel(VkDevice device, VkObjectType objectType, std::uint64_t objectHandle, const char* label) {
if (!vkSetDebugUtilsObjectNameEXT || device == VK_NULL_HANDLE || objectHandle == 0 || label == nullptr) {
return;
}
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{ const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_IMAGE, .objectType = objectType,
.objectHandle = (std::uint64_t)image, .objectHandle = objectHandle,
.pObjectName = label, .pObjectName = label,
}; };
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo); vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void vkutil::addDebugLabel(VkDevice device, VkImage image, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_IMAGE, reinterpret_cast<std::uint64_t>(image), label);
}
void vkutil::addDebugLabel(VkDevice device, VkImageView imageView, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_IMAGE_VIEW, reinterpret_cast<std::uint64_t>(imageView), label);
} }
void vkutil::addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label) { void vkutil::addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{ addDebugLabel(device, VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast<std::uint64_t>(shaderModule), label);
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_SHADER_MODULE,
.objectHandle = (std::uint64_t)shaderModule,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
} }
void vkutil::addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label) { void vkutil::addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{ addDebugLabel(device, VK_OBJECT_TYPE_PIPELINE, reinterpret_cast<std::uint64_t>(pipeline), label);
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, }
.objectType = VK_OBJECT_TYPE_PIPELINE,
.objectHandle = (std::uint64_t)pipeline, void vkutil::addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label) {
.pObjectName = label, addDebugLabel(device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, reinterpret_cast<std::uint64_t>(layout), label);
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
} }
void vkutil::addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) { void vkutil::addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{ addDebugLabel(device, VK_OBJECT_TYPE_BUFFER, reinterpret_cast<std::uint64_t>(buffer), label);
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_BUFFER,
.objectHandle = (std::uint64_t)buffer,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
} }
void vkutil::addDebugLabel(VkDevice device, VkSampler sampler, const char* label) { void vkutil::addDebugLabel(VkDevice device, VkSampler sampler, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{ addDebugLabel(device, VK_OBJECT_TYPE_SAMPLER, reinterpret_cast<std::uint64_t>(sampler), label);
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, }
.objectType = VK_OBJECT_TYPE_SAMPLER,
.objectHandle = (std::uint64_t)sampler, void vkutil::addDebugLabel(VkDevice device, VkDescriptorPool descriptorPool, const char* label) {
.pObjectName = label, addDebugLabel(device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, reinterpret_cast<std::uint64_t>(descriptorPool), label);
}
void vkutil::addDebugLabel(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, reinterpret_cast<std::uint64_t>(descriptorSetLayout), label);
}
void vkutil::addDebugLabel(VkDevice device, VkDescriptorSet descriptorSet, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_DESCRIPTOR_SET, reinterpret_cast<std::uint64_t>(descriptorSet), label);
}
void vkutil::addDebugLabel(VkDevice device, VkCommandPool commandPool, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_COMMAND_POOL, reinterpret_cast<std::uint64_t>(commandPool), label);
}
void vkutil::addDebugLabel(VkDevice device, VkCommandBuffer commandBuffer, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_COMMAND_BUFFER, reinterpret_cast<std::uint64_t>(commandBuffer), label);
}
void vkutil::addDebugLabel(VkDevice device, VkFence fence, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_FENCE, reinterpret_cast<std::uint64_t>(fence), label);
}
void vkutil::addDebugLabel(VkDevice device, VkSemaphore semaphore, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_SEMAPHORE, reinterpret_cast<std::uint64_t>(semaphore), label);
}
void vkutil::addDebugLabel(VkDevice device, VkQueue queue, const char* label) {
addDebugLabel(device, VK_OBJECT_TYPE_QUEUE, reinterpret_cast<std::uint64_t>(queue), label);
}
bool vkutil::debugLabelsEnabled() {
return vkCmdBeginDebugUtilsLabelEXT != nullptr && vkCmdEndDebugUtilsLabelEXT != nullptr;
}
void vkutil::cmdBeginLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color) {
if (!debugLabelsEnabled() || label == nullptr) {
return;
}
const auto labelInfo = VkDebugUtilsLabelEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
.pLabelName = label,
.color = {color.x, color.y, color.z, color.w},
}; };
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo); vkCmdBeginDebugUtilsLabelEXT(cmd, &labelInfo);
}
void vkutil::cmdEndLabel(VkCommandBuffer cmd) {
if (!debugLabelsEnabled()) {
return;
}
vkCmdEndDebugUtilsLabelEXT(cmd);
}
void vkutil::cmdInsertLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color) {
if (!vkCmdInsertDebugUtilsLabelEXT || label == nullptr) {
return;
}
const auto labelInfo = VkDebugUtilsLabelEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
.pLabelName = label,
.color = {color.x, color.y, color.z, color.w},
};
vkCmdInsertDebugUtilsLabelEXT(cmd, &labelInfo);
}
vkutil::ScopedCmdLabel::ScopedCmdLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color)
: cmd(cmd) {
cmdBeginLabel(cmd, label, color);
}
vkutil::ScopedCmdLabel::~ScopedCmdLabel() {
cmdEndLabel(cmd);
} }
vkutil::RenderInfo vkutil::createRenderingInfo(const RenderingInfoParams& params) { vkutil::RenderInfo vkutil::createRenderingInfo(const RenderingInfoParams& params) {
@@ -319,76 +389,6 @@ VkShaderModule vkutil::loadShaderModule(const std::filesystem::path& path, VkDev
return shaderModule; return shaderModule;
} }
void addDebugLabel(VkDevice device, VkImage image, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_IMAGE,
.objectHandle = (std::uint64_t)image,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_IMAGE_VIEW,
.objectHandle = (std::uint64_t)imageView,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_SHADER_MODULE,
.objectHandle = (std::uint64_t)shaderModule,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_PIPELINE,
.objectHandle = (std::uint64_t)pipeline,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_PIPELINE_LAYOUT,
.objectHandle = (std::uint64_t)layout,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_BUFFER,
.objectHandle = (std::uint64_t)buffer,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
void addDebugLabel(VkDevice device, VkSampler sampler, const char* label) {
const auto nameInfo = VkDebugUtilsObjectNameInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = VK_OBJECT_TYPE_SAMPLER,
.objectHandle = (std::uint64_t)sampler,
.pObjectName = label,
};
if (vkSetDebugUtilsObjectNameEXT) vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
vkutil::RenderInfo createRenderingInfo(const vkutil::RenderingInfoParams& params) { vkutil::RenderInfo createRenderingInfo(const vkutil::RenderingInfoParams& params) {
return vkutil::createRenderingInfo(params); return vkutil::createRenderingInfo(params);
} }
+110 -98
View File
@@ -153,65 +153,65 @@ void LightKeeper::customInit()
characterModelOptions.loadSkeleton = true; characterModelOptions.loadSkeleton = true;
characterModelOptions.loadAnimations = true; characterModelOptions.loadAnimations = true;
// auto charModel = ModelDoc::LoadModel( auto charModel = ModelDoc::LoadModel(
// AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(), AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
// characterModelOptions characterModelOptions
// ); );
// ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx"); ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
//
// const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow( const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
// charModel, charModel,
// "engine://cotw-capybara-male/source/capybara.fbx" "engine://cotw-capybara-male/source/capybara.fbx"
// ); );
//
// const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh); const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
//
// const auto charTexturePath = ModelDocUtils::PickTexturePath( const auto charTexturePath = ModelDocUtils::PickTexturePath(
// charModel, charModel,
// charPrimitive, charPrimitive,
// AssetFS::GetInstance().GetFullPath( AssetFS::GetInstance().GetFullPath(
// "engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs") "engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
// ); );
//
// const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath); const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
// // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg")); // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
// const auto charMaterialID = resources.materials().addMaterial({ const auto charMaterialID = resources.materials().addMaterial({
// .baseColor = ModelDocUtils::GetImportedBaseColor( .baseColor = ModelDocUtils::GetImportedBaseColor(
// charModel, charPrimitive), charModel, charPrimitive),
// .diffuseTexture = charTextureID, .diffuseTexture = charTextureID,
// .name = ModelDocUtils::GetImportedMaterialName( .name = ModelDocUtils::GetImportedMaterialName(
// charModel, charPrimitive, "CharacterMaterial"), charModel, charPrimitive, "CharacterMaterial"),
// }); });
//
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>(); const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
// charMeshComp->SetMeshID(charMeshID); charMeshComp->SetMeshID(charMeshID);
// charMeshComp->SetMaterialID(charMaterialID); charMeshComp->SetMaterialID(charMaterialID);
//
// const auto animator = CharObj->AddComponent<Animator>(); const auto animator = CharObj->AddComponent<Animator>();
// animator->setSkeleton(std::move(charModel.skeleton)); animator->setSkeleton(std::move(charModel.skeleton));
//
// std::string firstAnimationName; std::string firstAnimationName;
//
// for (auto& clip : charModel.animations) for (auto& clip : charModel.animations)
// { {
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration); spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
//
// if (firstAnimationName.empty()) if (firstAnimationName.empty())
// firstAnimationName = clip.name; firstAnimationName = clip.name;
//
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip))); animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
// } }
//
// if (!firstAnimationName.empty()) if (!firstAnimationName.empty())
// { {
// spdlog::info("Playing animation: '{}'", firstAnimationName); spdlog::info("Playing animation: '{}'", firstAnimationName);
// animator->play(firstAnimationName); animator->play(firstAnimationName);
// } }
//
// animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run"); animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
//
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f)); CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
// CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f); CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
// ModelDoc::LoadOptions options{}; // ModelDoc::LoadOptions options{};
// options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode; // options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
@@ -450,46 +450,58 @@ void LightKeeper::customInit()
triggerObj->GetTransform().SetWorldPosition({0.0f, 0.0f, 0.0f}); triggerObj->GetTransform().SetWorldPosition({0.0f, 0.0f, 0.0f});
// Forward+ test lights: a dim sun and a ring of colored point lights orbiting the origin // Forward+ test lights: a dim sun and a ring of colored point lights orbiting the origin
auto sunObj = scene.CreateGameObject("Sun"); // auto sunObj = scene.CreateGameObject("Sun");
auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional); // auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f}); // sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
sun->SetIntensity(1.0f); // sun->SetIntensity(1.0f);
sunObj->GetTransform().SetWorldRotation(glm::vec3{-50.0f, 30.0f, 0.0f}); // sun->SetCastShadows(true);
// sunObj->GetTransform().SetWorldRotation(glm::vec3{-50.0f, 30.0f, 0.0f});
//
// // static shadow casters, so the sun's shadows are visible without spawning balls
// for (int i = 0; i < 3; i++)
// {
// auto casterObj = scene.CreateGameObject("ShadowCaster " + std::to_string(i));
// auto* casterMesh = casterObj->AddComponent<MeshRendererComponent>();
// casterMesh->SetMeshID(sphereMesh);
// casterMesh->SetMaterialID(sphereMaterial);
// casterObj->GetTransform().SetWorldPosition(glm::vec3{-4.0f + 4.0f * static_cast<float>(i), 0.5f, 3.0f});
// casterObj->GetTransform().SetWorldScale(glm::vec3{0.015f});
// }
//
// constexpr int pointLightCount = 32;
// constexpr float pointLightRingRadius = 6.0f;
// for (int i = 0; i < pointLightCount; i++)
// {
// const float t = static_cast<float>(i) / static_cast<float>(pointLightCount);
// const float angle = t * glm::two_pi<float>();
//
// auto lightObj = scene.CreateGameObject("PointLight " + std::to_string(i));
// lightObj->GetTransform().SetWorldPosition(glm::vec3{
// std::cos(angle) * pointLightRingRadius,
// -0.25f,
// std::sin(angle) * pointLightRingRadius
// });
//
// auto* light = lightObj->AddComponent<LightComponent>(LightType::Point);
// light->SetColor(glm::vec3{
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * t),
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.33f)),
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.67f))
// });
// light->SetIntensity(1.0f);
// light->SetRange(3.0f);
//
// auto* orbit = lightObj->AddComponent<Rotator>(pointLightRingRadius, 0.5f);
// orbit->SetAxis(glm::vec3{0.0f, 1.0f, 0.0f});
// orbit->SetPivotPosition(glm::vec3{0.0f, -0.25f, 0.0f});
// }
constexpr int pointLightCount = 32; // auto playerObj = scene.CreateGameObject("Player");
constexpr float pointLightRingRadius = 6.0f; // playerObj->GetTransform().SetWorldPosition(glm::vec3(0.0f, 2.0f, -5.0f));
for (int i = 0; i < pointLightCount; i++) // auto* fps = playerObj->AddComponent<FirstPersonController>();
{ // m_Player = playerObj;
const float t = static_cast<float>(i) / static_cast<float>(pointLightCount); // m_FPSController = fps;
const float angle = t * glm::two_pi<float>(); // scene.GetPhysics().RegisterGameObject(*playerObj);
auto lightObj = scene.CreateGameObject("PointLight " + std::to_string(i));
lightObj->GetTransform().SetWorldPosition(glm::vec3{
std::cos(angle) * pointLightRingRadius,
-0.25f,
std::sin(angle) * pointLightRingRadius
});
auto* light = lightObj->AddComponent<LightComponent>(LightType::Point);
light->SetColor(glm::vec3{
0.5f + 0.5f * std::cos(glm::two_pi<float>() * t),
0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.33f)),
0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.67f))
});
light->SetIntensity(1.0f);
light->SetRange(3.0f);
auto* orbit = lightObj->AddComponent<Rotator>(pointLightRingRadius, 0.5f);
orbit->SetAxis(glm::vec3{0.0f, 1.0f, 0.0f});
orbit->SetPivotPosition(glm::vec3{0.0f, -0.25f, 0.0f});
}
auto playerObj = scene.CreateGameObject("Player");
playerObj->GetTransform().SetWorldPosition(glm::vec3(0.0f, 2.0f, -5.0f));
auto* fps = playerObj->AddComponent<FirstPersonController>();
m_Player = playerObj;
m_FPSController = fps;
scene.GetPhysics().RegisterGameObject(*playerObj);
const auto texPath = AssetFS::GetInstance().GetFullPath("engine://textures/kobe.png"); const auto texPath = AssetFS::GetInstance().GetFullPath("engine://textures/kobe.png");
texID = resources.loadImageFromFile(gfxDevice, texPath); texID = resources.loadImageFromFile(gfxDevice, texPath);
+3
View File
@@ -457,6 +457,7 @@ namespace {
light->SetIntensity(4.0f); light->SetIntensity(4.0f);
light->SetRange(7.5f); light->SetRange(7.5f);
light->SetConeAngles(0.2f, 0.4f); light->SetConeAngles(0.2f, 0.4f);
light->SetCastShadows(true);
const auto data = light->Serialize(); const auto data = light->Serialize();
@@ -472,6 +473,8 @@ namespace {
"LightComponent must round-trip intensity and range"); "LightComponent must round-trip intensity and range");
check(loaded->GetInnerConeAngle() == 0.2f && loaded->GetOuterConeAngle() == 0.4f, check(loaded->GetInnerConeAngle() == 0.2f && loaded->GetOuterConeAngle() == 0.4f,
"LightComponent must round-trip its cone angles"); "LightComponent must round-trip its cone angles");
check(loaded->GetCastShadows(),
"LightComponent must round-trip its cast shadows flag");
loaded->SetConeAngles(0.5f, 0.1f); loaded->SetConeAngles(0.5f, 0.1f);
check(loaded->GetOuterConeAngle() >= loaded->GetInnerConeAngle(), check(loaded->GetOuterConeAngle() >= loaded->GetInnerConeAngle(),