diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index 3907b68f..6f6fd64a 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -30,7 +30,7 @@ jobs: - name: Install Vulkan SDK uses: humbletim/install-vulkan-sdk@c2aa128094d42ba02959a660f03e0a4e012192f9 with: - version: latest + version: 1.3.296.0 cache: true - name: Configure CMake diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fbabb9b..29cea602 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,14 @@ cmake_minimum_required(VERSION 3.28) project(WillEngine) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) add_definitions(-DVK_NO_PROTOTYPES) + add_definitions(-DGLM_FORCE_DEPTH_ZERO_TO_ONE) add_definitions(-DGLM_ENABLE_EXPERIMENTAL) -add_definitions(-DJPH_DEBUG_RENDERER) + #add_definitions(-DJPH_PROFILE_ENABLED=0) -#add_definitions(-DJPH_DEBUG_RENDERER=0) add_definitions(-DJPH_ENABLE_ASSERTS=1) add_definitions(-DJPH_ENABLE_ASSERT_MESSAGES=1) @@ -16,6 +16,7 @@ add_definitions(-DJPH_ENABLE_ASSERT_MESSAGES=1) # ##endif if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions(-DWILL_ENGINE_DEBUG=1) + add_definitions(-DJPH_DEBUG_RENDERER) elseif (CMAKE_BUILD_TYPE STREQUAL "Release") add_definitions(-DWILL_ENGINE_RELEASE=1) endif () @@ -48,7 +49,7 @@ add_subdirectory(extern/fastgltf/deps) # simdjson # Jolt Physics set(PHYSICS_REPO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/extern/JoltPhysics") include(extern/JoltPhysics/Jolt/Jolt.cmake) -set(CMAKE_CXX_STANDARD 20) # Jolt sets it to 17 +set(CMAKE_CXX_STANDARD 23) # Jolt sets it to 17 include_directories(${CMAKE_SOURCE_DIR}) @@ -131,8 +132,8 @@ set(PHYSICS_SOURCES src/physics/physics_utils.h src/physics/physics_utils.cpp src/physics/physics_constants.h - src/physics/debug/debug_renderer.cpp - src/physics/debug/debug_renderer.h + src/physics/debug/jolt_debug_renderer.cpp + src/physics/debug/jolt_debug_renderer.h src/physics/physics_body.h ) @@ -263,7 +264,13 @@ set(TEMP_SOURCES src/renderer/pipelines/geometry/transparent_pipeline/transparent_pipeline_types.h src/renderer/pipelines/basic/basic_compute/basic_compute_pipeline_types.h src/renderer/pipelines/visibility_pass/visibility_pass_pipeline_types.h - + src/renderer/pipelines/debug/debug_renderer.cpp + src/renderer/pipelines/debug/debug_renderer.h + src/renderer/pipelines/debug/debug_renderer_types.h + src/renderer/pipelines/debug/debug_composite_pipeline.cpp + src/renderer/pipelines/debug/debug_composite_pipeline.h + src/renderer/pipelines/debug/debug_highlighter.cpp + src/renderer/pipelines/debug/debug_highlighter.h ) add_executable(WillEngine main.cpp diff --git a/assets/settings.willengine b/assets/settings.willengine index 8dd9b130..5a2ea691 100644 --- a/assets/settings.willengine +++ b/assets/settings.willengine @@ -9,18 +9,18 @@ }, "cameraSettings": { "position": [ - -19.169994354248047, - 105.9618911743164, - 36.455501556396484 + -7.438582420349121, + 34.399600982666016, + 47.61833953857422 ], "rotation": [ - -0.14886538684368134, - -0.2690022885799408, - -0.04212456941604614, - 0.9506327509880066 + 0.025229064747691154, + -0.12272556871175766, + 0.0031201005913317204, + 0.9921150803565979 ], "fov": 1.3089969158172607, - "aspectRatio": 1.4861111640930176, + "aspectRatio": 1.7777777910232544, "nearPlane": 1000.0, "farPlane": 0.10000000149011612 }, diff --git a/shaders/ambient_occlusion/ground_truth/gtao_main_pass.comp b/shaders/ambient_occlusion/ground_truth/gtao_main_pass.comp index ad21dd10..a3746419 100644 --- a/shaders/ambient_occlusion/ground_truth/gtao_main_pass.comp +++ b/shaders/ambient_occlusion/ground_truth/gtao_main_pass.comp @@ -132,6 +132,7 @@ void main() { // Get view space normal by sampling normal buffer and converting from world to view (code not relevant) vec3 viewNormal = texture(normalBuffer, uv).rgb; + viewNormal = unpackNormal(viewNormal); if (pushConstants.debug == 2){ imageStore(debugImage, screenPos, vec4(viewNormal, 1.0f)); diff --git a/shaders/debug/debug_composite.comp b/shaders/debug/debug_composite.comp new file mode 100644 index 00000000..c468e0af --- /dev/null +++ b/shaders/debug/debug_composite.comp @@ -0,0 +1,29 @@ +#version 460 + +#include "scene.glsl" + +layout (local_size_x = 16, local_size_y = 16) in; + +// layout (std140, set = 0, binding = 0) uniform SceneData - scene.glsl + +layout(set = 1, binding = 0) uniform sampler2D debugImage; +layout(set = 1, binding = 1, rgba16) uniform image2D finalImage; + +void main() { + ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pixelCoord, ivec2(sceneData.renderTargetSize)))) { + return; + } + vec2 uv = (vec2(pixelCoord) + 0.5) / sceneData.renderTargetSize; + vec4 mainColor = imageLoad(finalImage, pixelCoord); + + vec2 debugUv = uv; + // Flip (Main image is flipped in PP) + debugUv.y = 1 - debugUv.y; + // Unjitter + debugUv += sceneData.jitter.xy / 2.0f; + vec4 debugColor = texture(debugImage, debugUv); + + vec4 finalColor = mix(mainColor, debugColor, debugColor.a); + imageStore(finalImage, pixelCoord, finalColor); +} \ No newline at end of file diff --git a/shaders/debug/debug_highlighter.frag b/shaders/debug/debug_highlighter.frag new file mode 100644 index 00000000..59de6425 --- /dev/null +++ b/shaders/debug/debug_highlighter.frag @@ -0,0 +1,9 @@ +#version 460 + +layout (location = 0) in vec3 inColor; + +layout (location = 0) out vec4 imageTarget; + +void main() { + imageTarget = vec4(inColor, 1.0); +} diff --git a/shaders/debug/debug_highlighter.vert b/shaders/debug/debug_highlighter.vert new file mode 100644 index 00000000..0ef23564 --- /dev/null +++ b/shaders/debug/debug_highlighter.vert @@ -0,0 +1,21 @@ +#version 460 + +#include "scene.glsl" + +layout(location = 0) in vec3 inPosition; + +layout(location = 0) out vec3 outColor; + +// layout (std140, set = 0, binding = 0) uniform SceneData - scene.glsl + +layout (push_constant) uniform PushConstants { + mat4 modelMatrix; + vec4 color; +} push; + +void main() { + gl_Position = sceneData.viewProj * push.modelMatrix * vec4(inPosition, 1.0); + // fixed depth offset so that the whole object can be seen in most cases + gl_Position.z += 0.001; + outColor = push.color.xyz; +} \ No newline at end of file diff --git a/shaders/debug/debug_highlighter_processing.comp b/shaders/debug/debug_highlighter_processing.comp new file mode 100644 index 00000000..54fbfe80 --- /dev/null +++ b/shaders/debug/debug_highlighter_processing.comp @@ -0,0 +1,60 @@ +#version 460 + +#include "scene.glsl" + +layout (local_size_x = 16, local_size_y = 16) in; + +// layout (std140, set = 0, binding = 0) uniform SceneData - scene.glsl + +layout(set = 1, binding = 0, r8ui) uniform uimage2D highlighterStencil; +layout(set = 1, binding = 1, rgba16) uniform image2D debugTarget; + +const int OUTLINE_THICKNESS = 2; + +void main() { + ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThan(pixelCoord, ivec2(sceneData.renderTargetSize)))) { + return; + } + + uint stencilValue = imageLoad(highlighterStencil, pixelCoord).r; + + if (stencilValue == 0) { + return; + } + + bool isEdge = false; + + for (int thickness = 1; thickness <= OUTLINE_THICKNESS; thickness++) { + for (int dir = 0; dir < 4; dir++) { + ivec2 offset; + if (dir == 0) offset = ivec2(thickness, 0); // Right + if (dir == 1) offset = ivec2(-thickness, 0); // Left + if (dir == 2) offset = ivec2(0, thickness); // Down + if (dir == 3) offset = ivec2(0, -thickness); // Up + + ivec2 neighborCoord = pixelCoord + offset; + + if (all(greaterThanEqual(neighborCoord, ivec2(0))) && + all(lessThan(neighborCoord, ivec2(sceneData.renderTargetSize)))) { + uint neighborValue = imageLoad(highlighterStencil, neighborCoord).r; + if (neighborValue == 0) { + isEdge = true; + break; + } + } else { + isEdge = true; + break; + } + } + + if (isEdge) { + break; + } + } + + if (isEdge) { + vec4 outlineColor = vec4(1.0, 0.647, 0.0, 1.0); + imageStore(debugTarget, pixelCoord, outlineColor); + } +} \ No newline at end of file diff --git a/shaders/debug/debug_renderer.frag b/shaders/debug/debug_renderer.frag new file mode 100644 index 00000000..e7bfb980 --- /dev/null +++ b/shaders/debug/debug_renderer.frag @@ -0,0 +1,10 @@ +#version 460 + +layout (location = 0) in vec3 inColor; + +layout (location = 0) out vec4 imageTarget; + +void main() { + // 0 indicates this won't do light calculations in deferred resolve + imageTarget = vec4(inColor, 1.0); +} diff --git a/shaders/debug/debug_renderer.vert b/shaders/debug/debug_renderer.vert new file mode 100644 index 00000000..fcec9ef0 --- /dev/null +++ b/shaders/debug/debug_renderer.vert @@ -0,0 +1,16 @@ +#version 460 + +#include "scene.glsl" + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; + +layout(location = 0) out vec3 outColor; + +// layout (std140, set = 0, binding = 0) uniform SceneData - scene.glsl + +void main() { + gl_Position = sceneData.viewProj * vec4(inPosition, 1.0); + gl_Position.xy += gl_Position.w * sceneData.jitter.xy; + outColor = inColor; +} \ No newline at end of file diff --git a/shaders/debug/debug_renderer_instanced.frag b/shaders/debug/debug_renderer_instanced.frag new file mode 100644 index 00000000..e7bfb980 --- /dev/null +++ b/shaders/debug/debug_renderer_instanced.frag @@ -0,0 +1,10 @@ +#version 460 + +layout (location = 0) in vec3 inColor; + +layout (location = 0) out vec4 imageTarget; + +void main() { + // 0 indicates this won't do light calculations in deferred resolve + imageTarget = vec4(inColor, 1.0); +} diff --git a/shaders/debug/debug_renderer_instanced.vert b/shaders/debug/debug_renderer_instanced.vert new file mode 100644 index 00000000..2f718f19 --- /dev/null +++ b/shaders/debug/debug_renderer_instanced.vert @@ -0,0 +1,26 @@ +#version 460 + +layout(location = 0) in vec3 inPosition; + +layout(location = 0) out vec3 outColor; + +#include "scene.glsl" + +struct Instance{ + mat4 transform; + vec3 color; + float padding; +}; + +// layout (std140, set = 0, binding = 0) uniform SceneData - scene.glsl + +layout(std140, set = 1, binding = 0) readonly buffer InstanceBuffer { + Instance instances[]; +} instances; + +void main() { + Instance instance = instances.instances[gl_InstanceIndex]; + gl_Position = sceneData.viewProj * instance.transform * vec4(inPosition, 1.0); + gl_Position.xy += gl_Position.w * sceneData.jitter.xy; + outColor = instance.color; +} \ No newline at end of file diff --git a/shaders/deferredMrt.frag b/shaders/deferredMrt.frag index 47eaca35..305c5148 100644 --- a/shaders/deferredMrt.frag +++ b/shaders/deferredMrt.frag @@ -73,8 +73,7 @@ void main() { roughness *= metalRoughSample.g; } - - normalTarget = vec4(normalize(inViewNormal), 0.0f); + normalTarget = vec4(packNormal(normalize(inViewNormal)), 0.0f); albedoTarget = vec4(albedo.xyz, 1.0f); pbrTarget = vec4(metallic, roughness, 0.0f, inHasTransparent); diff --git a/shaders/deferredResolve.comp b/shaders/deferredResolve.comp index 08fd8fee..698d9d7e 100644 --- a/shaders/deferredResolve.comp +++ b/shaders/deferredResolve.comp @@ -1,6 +1,7 @@ #version 460 #extension GL_EXT_nonuniform_qualifier: enable +#include "common.glsl" #include "scene.glsl" #include "pbr.glsl" #include "environment.glsl" @@ -86,6 +87,8 @@ void main() { } float depth = texture(depthBuffer, uv).r; vec3 viewNormal = texture(normalRenderTarget, uv).rgb; + viewNormal = unpackNormal(viewNormal); + vec4 pbrData = texture(pbrRenderTarget, uv); vec3 viewPosition = reconstructPosition(uv, depth); @@ -174,7 +177,7 @@ void main() { imageStore(outputImage, screenPos, albedo); break; case 4: - imageStore(outputImage, screenPos, vec4(worldN * 0.5f + 0.5f, 1.0f)); + imageStore(outputImage, screenPos, vec4(packNormal(viewNormal), 1.0f)); break; case 5: imageStore(outputImage, screenPos, pbrData); diff --git a/shaders/environment/environment.frag b/shaders/environment/environment.frag index dd53a94c..3f707d88 100644 --- a/shaders/environment/environment.frag +++ b/shaders/environment/environment.frag @@ -1,5 +1,6 @@ #version 450 +#include "common.glsl" #include "scene.glsl" layout (location = 0) in vec3 uv; @@ -21,11 +22,10 @@ void main() direction.y = -direction.y; vec3 envColor = textureLod(environmentMap, direction, 0).rgb; - // 0 = environment map flag + // 0 = "do not calculate lighting" flag albedoTarget = vec4(envColor, 0.0); - vec3 normal = mat3(sceneData.view) * -direction; - normalTarget = vec4(normal, 0.0f); + normalTarget = vec4(packNormal(mat3(sceneData.view) * -direction), 0.0f); pbrTarget = vec4(0.0f); vec2 currNdc = inCurrMvpPosition.xy / inCurrMvpPosition.w; diff --git a/shaders/include/common.glsl b/shaders/include/common.glsl index e3b65769..81363fb2 100644 --- a/shaders/include/common.glsl +++ b/shaders/include/common.glsl @@ -47,4 +47,20 @@ bool nearlyEqual(float a, float b, float epsilon) { return abs(a - b) <= epsilon; } +vec3 unpackNormal(vec3 packedNormal) { + #ifdef REMAP_NORMALS + return packedNormal * 2.0 - 1.0; + #else + return packedNormal; + #endif +} + +vec3 packNormal(vec3 normal) { + #ifdef REMAP_NORMALS + return normal * 0.5 + 0.5; + #else + return normal; + #endif +} + #endif // COMMON_GLSL \ No newline at end of file diff --git a/shaders/terrain/terrain.frag b/shaders/terrain/terrain.frag index 4f2dfd81..6cee5061 100644 --- a/shaders/terrain/terrain.frag +++ b/shaders/terrain/terrain.frag @@ -3,10 +3,10 @@ #extension GL_EXT_buffer_reference: require #extension GL_EXT_nonuniform_qualifier: enable +#include "common.glsl" #include "scene.glsl" #include "structure.glsl" - // world space layout (location = 0) in vec3 inPosition; layout (location = 1) in vec3 inNormal; @@ -41,7 +41,7 @@ float smoothBlend(float value, float threshold, float range) { } void main() { - normalTarget = vec4(mat3(sceneData.view) * normalize(inNormal), 0.0f); + normalTarget = vec4(packNormal(mat3(sceneData.view) * normalize(inNormal)), 0.0f);; float slope = 1.0 - abs(dot(normalize(inNormal), vec3(0.0, 1.0, 0.0))); float height = inPosition.y; diff --git a/src/core/camera/free_camera.h b/src/core/camera/free_camera.h index 875fc3e7..1a1a1325 100644 --- a/src/core/camera/free_camera.h +++ b/src/core/camera/free_camera.h @@ -15,9 +15,8 @@ namespace will_engine */ class FreeCamera final : public Camera { public: - FreeCamera() = default; - - FreeCamera(float fov, float aspect, float nearPlane, float farPlane); + explicit FreeCamera(float fov = 1.308996939f, float aspect = RENDER_EXTENT_WIDTH / RENDER_EXTENT_HEIGHT, float nearPlane = 1000.0f, + float farPlane = 0.1f); ~FreeCamera() override = default; diff --git a/src/core/engine.cpp b/src/core/engine.cpp index e068a83f..4d2f6b2e 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -24,7 +24,12 @@ #include "src/renderer/assets/render_object/render_object.h" #include "src/renderer/descriptor_buffer/descriptor_buffer_uniform.h" #include "src/renderer/environment/environment.h" -#include "../renderer/pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.h" +#if WILL_ENGINE_DEBUG +#include "src/renderer/pipelines/debug/debug_composite_pipeline.h" +#include "src/renderer/pipelines/debug/debug_highlighter.h" +#endif // !WILL_ENGINE_DEBUG +#include "src/renderer/pipelines/debug/debug_renderer.h" +#include "src/renderer/pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.h" #include "src/renderer/pipelines/geometry/deferred_mrt/deferred_mrt_pipeline.h" #include "src/renderer/pipelines/geometry/deferred_mrt/deferred_mrt_pipeline_types.h" #include "src/renderer/pipelines/geometry/deferred_resolve/deferred_resolve_pipeline.h" @@ -76,7 +81,7 @@ void Engine::init() // We initialize SDL and create a window with it. SDL_Init(SDL_INIT_VIDEO); constexpr auto window_flags = SDL_WINDOW_VULKAN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE; - windowExtent = {1920, 1080}; + windowExtent = {RENDER_EXTENTS.width, RENDER_EXTENTS.height}; //auto window_flags = static_cast(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE); @@ -96,9 +101,8 @@ void Engine::init() startupProfiler.addEntry("Vulkan Context"); createSwapchain(windowExtent.width, windowExtent.height); - createDrawResources(); - startupProfiler.addEntry("Swapchain/Draw Resources"); + startupProfiler.addEntry("Swapchain"); // Command Pools const VkCommandPoolCreateInfo commandPoolInfo = vk_helpers::commandPoolCreateInfo(context->graphicsQueueFamily, @@ -126,6 +130,18 @@ void Engine::init() assetManager = new AssetManager(*resourceManager); physics = new physics::Physics(); physics::Physics::set(physics); + + createDrawResources(); + +#if WILL_ENGINE_DEBUG + debugRenderer = new debug_renderer::DebugRenderer(*resourceManager); + debug_renderer::DebugRenderer::set(debugRenderer); + debugPipeline = new debug_pipeline::DebugCompositePipeline(*resourceManager); + debugPipeline->setupDescriptorBuffer(debugTarget.imageView, finalImageBuffer.imageView); + debugHighlighter = new debug_highlight_pipeline::DebugHighlighter(*resourceManager); + debugHighlighter->setupDescriptorBuffer(stencilImageView, debugTarget.imageView); +#endif + startupProfiler.addEntry("Immediate, ResourceM, AssetM, Physics"); environmentMap = new environment::Environment(*resourceManager, *immediate); @@ -212,16 +228,16 @@ void Engine::initRenderer() postProcessPipeline = new post_process_pipeline::PostProcessPipeline(*resourceManager); startupProfiler.addEntry("Init PP Pass"); - ambientOcclusionPipeline->setupDepthPrefilterDescriptorBuffer(depthImage.imageView); + ambientOcclusionPipeline->setupDepthPrefilterDescriptorBuffer(depthImageView); ambientOcclusionPipeline->setupAmbientOcclusionDescriptorBuffer(normalRenderTarget.imageView); ambientOcclusionPipeline->setupSpatialFilteringDescriptorBuffer(); - contactShadowsPipeline->setupDescriptorBuffer(depthImage.imageView); + contactShadowsPipeline->setupDescriptorBuffer(depthImageView); const deferred_resolve::DeferredResolveDescriptor deferredResolveDescriptor{ normalRenderTarget.imageView, albedoRenderTarget.imageView, pbrRenderTarget.imageView, - depthImage.imageView, + depthImageView, velocityRenderTarget.imageView, ambientOcclusionPipeline->getAmbientOcclusionRenderTarget().imageView, contactShadowsPipeline->getContactShadowRenderTarget().imageView, @@ -233,7 +249,7 @@ void Engine::initRenderer() const temporal_antialiasing_pipeline::TemporalAntialiasingDescriptor temporalAntialiasingDescriptor{ drawImage.imageView, historyBuffer.imageView, - depthImage.imageView, + depthImageView, velocityRenderTarget.imageView, taaResolveTarget.imageView, resourceManager->getDefaultSamplerLinear() @@ -243,7 +259,7 @@ void Engine::initRenderer() const post_process_pipeline::PostProcessDescriptor postProcessDescriptor{ taaResolveTarget.imageView, - postProcessOutputBuffer.imageView, + finalImageBuffer.imageView, resourceManager->getDefaultSamplerLinear() }; postProcessPipeline->setupDescriptorBuffer(postProcessDescriptor); @@ -325,11 +341,15 @@ void Engine::run() void Engine::updatePhysics(const float deltaTime) const { - if (bPausePhysics) { - return; + if (bEnablePhysics) { + physics::Physics::get()->update(deltaTime); } - physics::Physics::get()->update(deltaTime); +#if WILL_ENGINE_DEBUG + if (bDebugPhysics) { + physics::Physics::get()->drawDebug(); + } +#endif } void Engine::updateGame(const float deltaTime) @@ -352,11 +372,40 @@ void Engine::updateGame(const float deltaTime) } } + if (input.isKeyPressed(SDLK_G)) { + if (camera) { + if (auto transformable = dynamic_cast(selectedItem)) { + glm::vec3 itemPosition = transformable->getPosition(); + + glm::vec3 itemScale = transformable->getScale(); + float maxDimension = glm::max(glm::max(itemScale.x, itemScale.y), itemScale.z); + + float distance = glm::max(5.0f, maxDimension * 3.0f); + + glm::vec3 currentCamPos = camera->getTransform().getPosition(); + glm::vec3 currentDirection = glm::normalize(itemPosition - currentCamPos); + + glm::vec3 newCamPos = itemPosition - (currentDirection * distance); + + glm::vec3 forward = glm::normalize(newCamPos - itemPosition); + glm::vec3 right = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), forward)); + glm::vec3 up = glm::cross(forward, right); + + glm::mat3 rotMatrix(right, up, forward); + glm::quat newRotation = glm::quat_cast(rotMatrix); + + camera->setCameraTransform(newCamPos, newRotation); + } + } + } + for (IHierarchical* hierarchal : hierarchalBeginQueue) { hierarchal->beginPlay(); } hierarchalBeginQueue.clear(); + // This is the main game update loop. + // Recursively updates all child gameobjects of each map for (Map* map : activeMaps) { map->update(deltaTime); } @@ -372,6 +421,21 @@ void Engine::updateGame(const float deltaTime) delete hierarchical; } hierarchicalDeletionQueue.clear(); + + + constexpr glm::vec3 offset{-100, 100, 0}; + for (int32_t i{0}; i < 100; i++) { + for (int32_t j{0}; j < 100; j++) { + float z = glm::sin(Time::Get().getTime() - j * 0.5f) * 2.0; + debug_renderer::DebugRenderer::drawBox(offset + glm::vec3(i, j, z), {0.8f, 0.8f, 0.8f}, {0.0f, 0.7f, 0.1f}); + } + } + + debug_renderer::DebugRenderer::drawSphere({-50, 40, 0}, 1.0f, {0.0f, 0.7f, 0.1f}); + + debug_renderer::DebugRenderer::drawLine({0, 0, 0}, {0, 100, 0}, {1, 0, 0}); + + debug_renderer::DebugRenderer::drawTriangle({0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 1, 0}); } void Engine::updateRender(VkCommandBuffer cmd, const float deltaTime, const int32_t currentFrameOverlap, const int32_t previousFrameOverlap) const @@ -444,9 +508,9 @@ void Engine::updateRender(VkCommandBuffer cmd, const float deltaTime, const int3 pDebugSceneData->texelSize = {1.0f / RENDER_EXTENT_WIDTH, 1.0f / RENDER_EXTENT_HEIGHT}; pDebugSceneData->deltaTime = deltaTime; - vk_helpers::synchronizeUniform(cmd, sceneDataBuffer, VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, + vk_helpers::uniformBarrier(cmd, sceneDataBuffer, VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, VK_ACCESS_2_UNIFORM_READ_BIT); - vk_helpers::synchronizeUniform(cmd, debugSceneDataBuffer, VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, + vk_helpers::uniformBarrier(cmd, debugSceneDataBuffer, VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, VK_ACCESS_2_UNIFORM_READ_BIT); } @@ -479,7 +543,6 @@ void Engine::render(float deltaTime) profiler.beginTimer("2Render"); - std::vector allRenderObjects = assetManager->getAllRenderObjects(); // Update Render Object Buffers and Model Matrices @@ -522,15 +585,15 @@ void Engine::render(float deltaTime) vk_helpers::clearColorImage(cmd, VK_IMAGE_ASPECT_COLOR_BIT, drawImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - vk_helpers::transitionImage(cmd, depthImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, - VK_IMAGE_ASPECT_DEPTH_BIT); - vk_helpers::transitionImage(cmd, normalRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, depthStencilImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + vk_helpers::imageBarrier(cmd, normalRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, albedoRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, albedoRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, pbrRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, pbrRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, velocityRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, velocityRenderTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); environment_pipeline::EnvironmentDrawInfo environmentPipelineDrawInfo{ @@ -539,7 +602,7 @@ void Engine::render(float deltaTime) albedoRenderTarget.imageView, pbrRenderTarget.imageView, velocityRenderTarget.imageView, - depthImage.imageView, + depthImageView, sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), sceneDataDescriptorBuffer.getDescriptorBufferSize() * currentFrameOverlap, environmentMap->getCubemapDescriptorBuffer().getDescriptorBufferBindingInfo(), @@ -569,7 +632,7 @@ void Engine::render(float deltaTime) albedoRenderTarget.imageView, pbrRenderTarget.imageView, velocityRenderTarget.imageView, - depthImage.imageView, + depthImageView, sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), sceneDataDescriptorBuffer.getDescriptorBufferSize() * currentFrameOverlap }; @@ -584,7 +647,7 @@ void Engine::render(float deltaTime) albedoRenderTarget.imageView, pbrRenderTarget.imageView, velocityRenderTarget.imageView, - depthImage.imageView, + depthImageView, sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), sceneDataDescriptorBuffer.getDescriptorBufferSize() * currentFrameOverlap }; @@ -600,7 +663,7 @@ void Engine::render(float deltaTime) albedoRenderTarget.imageView, pbrRenderTarget.imageView, velocityRenderTarget.imageView, - depthImage.imageView, + depthImageView, sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), sceneDataDescriptorBuffer.getDescriptorBufferSize() * FRAME_OVERLAP }; @@ -609,7 +672,7 @@ void Engine::render(float deltaTime) transparent_pipeline::TransparentAccumulateDrawInfo transparentDrawInfo{ true, - depthImage.imageView, + depthImageView, currentFrameOverlap, allRenderObjects, sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), @@ -624,17 +687,18 @@ void Engine::render(float deltaTime) transparentPipeline->drawAccumulate(cmd, transparentDrawInfo); } - vk_helpers::transitionImage(cmd, normalRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, normalRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, albedoRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, albedoRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, pbrRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, pbrRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, velocityRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, velocityRenderTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, depthImage.image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_IMAGE_ASPECT_DEPTH_BIT); - vk_helpers::transitionImage(cmd, drawImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, depthStencilImage.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + vk_helpers::imageBarrier(cmd, drawImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); ambient_occlusion::GTAODrawInfo gtaoDrawInfo{ camera, @@ -674,7 +738,7 @@ void Engine::render(float deltaTime) }; deferredResolvePipeline->draw(cmd, deferredResolveDrawInfo); - vk_helpers::transitionImage(cmd, drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); transparent_pipeline::TransparentCompositeDrawInfo compositeDrawInfo{ drawImage.imageView }; @@ -682,11 +746,11 @@ void Engine::render(float deltaTime) transparentPipeline->drawComposite(cmd, compositeDrawInfo); } - vk_helpers::transitionImage(cmd, drawImage.image, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, drawImage.image, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); const VkImageLayout originLayout = frameNumber == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - vk_helpers::transitionImage(cmd, historyBuffer.image, originLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, taaResolveTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, historyBuffer.image, originLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, taaResolveTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); const temporal_antialiasing_pipeline::TemporalAntialiasingDrawInfo taaDrawInfo{ taaSettings.blendValue, @@ -697,15 +761,15 @@ void Engine::render(float deltaTime) temporalAntialiasingPipeline->draw(cmd, taaDrawInfo); // Copy to TAA History - vk_helpers::transitionImage(cmd, taaResolveTarget.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vk_helpers::imageBarrier(cmd, taaResolveTarget.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, historyBuffer.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + vk_helpers::imageBarrier(cmd, historyBuffer.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); vk_helpers::copyImageToImage(cmd, taaResolveTarget.image, historyBuffer.image, RENDER_EXTENTS, RENDER_EXTENTS); - vk_helpers::transitionImage(cmd, taaResolveTarget.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, taaResolveTarget.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, postProcessOutputBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, finalImageBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); const post_process_pipeline::PostProcessDrawInfo postProcessDrawInfo{ @@ -716,24 +780,95 @@ void Engine::render(float deltaTime) postProcessPipeline->draw(cmd, postProcessDrawInfo); - vk_helpers::transitionImage(cmd, postProcessOutputBuffer.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, +#if WILL_ENGINE_DEBUG + // Ensure all real rendering happens before this step, as debug draws do write to the depth buffer. + // This should ALWAYS be the final step before copying to swapchain + if (bDrawDebugRendering) { + vk_helpers::clearColorImage(cmd, VK_IMAGE_ASPECT_COLOR_BIT, debugTarget.image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, {0.0f, 0.0f, 0.0f, 0.0f}); + vk_helpers::imageBarrier(cmd, depthStencilImage.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + + debug_renderer::DebugRendererDrawInfo debugRendererDrawInfo{ + currentFrameOverlap, + debugTarget.imageView, + depthImageView, + sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), + sceneDataDescriptorBuffer.getDescriptorBufferSize() * currentFrameOverlap + }; + + debugRenderer->draw(cmd, debugRendererDrawInfo); + + bool stencilDrawn = false; + + debug_highlight_pipeline::DebugHighlighterDrawInfo highlightDrawInfo{ + nullptr, + depthStencilImage, + sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), + sceneDataDescriptorBuffer.getDescriptorBufferSize() * currentFrameOverlap + }; + + + if (IComponentContainer* cc = dynamic_cast(selectedItem)) { + if (components::MeshRendererComponent* meshRenderer = cc->getComponent()) { + highlightDrawInfo.highlightTarget = meshRenderer; + stencilDrawn = debugHighlighter->drawHighlightStencil(cmd, highlightDrawInfo); + } + } + + if (stencilDrawn) { + vk_helpers::imageBarrier(cmd, debugTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, depthStencilImage.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + + debugHighlighter->drawHighlightProcessing(cmd, highlightDrawInfo); + + + vk_helpers::imageBarrier(cmd, debugTarget.image, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_ASPECT_COLOR_BIT); + } + else { + vk_helpers::imageBarrier(cmd, debugTarget.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_ASPECT_COLOR_BIT); + } + + + debug_pipeline::DebugCompositePipelineDrawInfo drawInfo{ + sceneDataDescriptorBuffer.getDescriptorBufferBindingInfo(), + sceneDataDescriptorBuffer.getDescriptorBufferSize() * currentFrameOverlap + }; + + // Composite all draws in the debug image into `finalImageBuffer` + debugPipeline->draw(cmd, drawInfo); + } +#endif + vk_helpers::imageBarrier(cmd, finalImageBuffer.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + + vk_helpers::imageBarrier(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::copyImageToImage(cmd, postProcessOutputBuffer.image, swapchainImages[swapchainImageIndex], RENDER_EXTENTS, swapchainExtent); + vk_helpers::copyImageToImage(cmd, finalImageBuffer.image, swapchainImages[swapchainImageIndex], RENDER_EXTENTS, swapchainExtent); - vk_helpers::transitionImage(cmd, postProcessOutputBuffer.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, + vk_helpers::imageBarrier(cmd, finalImageBuffer.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); if (engine_constants::useImgui) { - vk_helpers::transitionImage(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); imguiWrapper->drawImgui(cmd, swapchainImageViews[swapchainImageIndex], swapchainExtent); - vk_helpers::transitionImage(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + vk_helpers::imageBarrier(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_ASPECT_COLOR_BIT); - } else { - vk_helpers::transitionImage(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + } + else { + vk_helpers::imageBarrier(cmd, swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_ASPECT_COLOR_BIT); } @@ -801,14 +936,15 @@ void Engine::cleanup() delete postProcessPipeline; for (AllocatedBuffer sceneBuffer : sceneDataBuffers) { - resourceManager->destroyBuffer(sceneBuffer); + resourceManager->destroy(sceneBuffer); + } + resourceManager->destroy(debugSceneDataBuffer); + resourceManager->destroy(sceneDataDescriptorBuffer); + + if (engine_constants::useImgui) { + delete imguiWrapper; } - resourceManager->destroyBuffer(debugSceneDataBuffer); - resourceManager->destroyDescriptorBuffer(sceneDataDescriptorBuffer); -#ifndef NDEBUG - delete imguiWrapper; -#endif for (const FrameData& frame : frames) { vkDestroyCommandPool(context->device, frame._commandPool, nullptr); @@ -819,15 +955,17 @@ void Engine::cleanup() vkDestroySemaphore(context->device, frame._swapchainSemaphore, nullptr); } - resourceManager->destroyImage(drawImage); - resourceManager->destroyImage(depthImage); - resourceManager->destroyImage(normalRenderTarget); - resourceManager->destroyImage(albedoRenderTarget); - resourceManager->destroyImage(pbrRenderTarget); - resourceManager->destroyImage(velocityRenderTarget); - resourceManager->destroyImage(taaResolveTarget); - resourceManager->destroyImage(historyBuffer); - resourceManager->destroyImage(postProcessOutputBuffer); + resourceManager->destroy(drawImage); + resourceManager->destroy(depthStencilImage); + resourceManager->destroy(depthImageView); + resourceManager->destroy(stencilImageView); + resourceManager->destroy(normalRenderTarget); + resourceManager->destroy(albedoRenderTarget); + resourceManager->destroy(pbrRenderTarget); + resourceManager->destroy(velocityRenderTarget); + resourceManager->destroy(taaResolveTarget); + resourceManager->destroy(historyBuffer); + resourceManager->destroy(finalImageBuffer); for (Map* map : activeMaps) { map->destroy(); @@ -850,7 +988,13 @@ void Engine::cleanup() delete cascadedShadowMap; delete environmentMap; - delete physics::Physics::get(); +#if WILL_ENGINE_DEBUG + resourceManager->destroy(debugTarget); + delete debugRenderer; + delete debugHighlighter; + delete debugPipeline; +#endif + delete physics; delete immediate; delete resourceManager; @@ -864,7 +1008,7 @@ void Engine::cleanup() SDL_DestroyWindow(window); } -IHierarchical* Engine::createGameObject(Map* map, const std::string& name) const +IHierarchical* Engine::createGameObject(Map* map, const std::string& name) { const auto newGameObject = new GameObject(name); map->addGameObject(newGameObject); @@ -965,22 +1109,32 @@ void Engine::createDrawResources() } // Depth Image { - depthImage.imageFormat = DEPTH_FORMAT; + depthStencilImage.imageFormat = DEPTH_STENCIL_FORMAT; constexpr VkExtent3D depthImageExtent = {RENDER_EXTENTS.width, RENDER_EXTENTS.height, 1}; - depthImage.imageExtent = depthImageExtent; + depthStencilImage.imageExtent = depthImageExtent; VkImageUsageFlags depthImageUsages{}; depthImageUsages |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; depthImageUsages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; depthImageUsages |= VK_IMAGE_USAGE_SAMPLED_BIT; - VkImageCreateInfo depthImageInfo = vk_helpers::imageCreateInfo(depthImage.imageFormat, depthImageUsages, depthImageExtent); + VkImageCreateInfo depthImageInfo = vk_helpers::imageCreateInfo(depthStencilImage.imageFormat, depthImageUsages, depthImageExtent); VmaAllocationCreateInfo depthImageAllocationInfo = {}; depthImageAllocationInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; depthImageAllocationInfo.requiredFlags = static_cast(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - vmaCreateImage(context->allocator, &depthImageInfo, &depthImageAllocationInfo, &depthImage.image, &depthImage.allocation, nullptr); + vmaCreateImage(context->allocator, &depthImageInfo, &depthImageAllocationInfo, &depthStencilImage.image, &depthStencilImage.allocation, + nullptr); - VkImageViewCreateInfo depthViewInfo = vk_helpers::imageviewCreateInfo(depthImage.imageFormat, depthImage.image, VK_IMAGE_ASPECT_DEPTH_BIT); - VK_CHECK(vkCreateImageView(context->device, &depthViewInfo, nullptr, &depthImage.imageView)); + VkImageViewCreateInfo combinedViewInfo = vk_helpers::imageviewCreateInfo(depthStencilImage.imageFormat, depthStencilImage.image, + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + VK_CHECK(vkCreateImageView(context->device, &combinedViewInfo, nullptr, &depthStencilImage.imageView)); + + VkImageViewCreateInfo depthViewInfo = vk_helpers::imageviewCreateInfo(depthStencilImage.imageFormat, depthStencilImage.image, + VK_IMAGE_ASPECT_DEPTH_BIT); + VK_CHECK(vkCreateImageView(context->device, &depthViewInfo, nullptr, &depthImageView)); + + VkImageViewCreateInfo stencilViewInfo = vk_helpers::imageviewCreateInfo(depthStencilImage.imageFormat, depthStencilImage.image, + VK_IMAGE_ASPECT_STENCIL_BIT); + VK_CHECK(vkCreateImageView(context->device, &stencilViewInfo, nullptr, &stencilImageView)); } // Render Targets { @@ -1058,26 +1212,38 @@ void Engine::createDrawResources() historyBuffer.imageFormat, historyBuffer.image, VK_IMAGE_ASPECT_COLOR_BIT); VK_CHECK(vkCreateImageView(context->device, &historyBufferImageViewInfo, nullptr, &historyBuffer.imageView)); } - // Post Process Resolve + // Final Image { - postProcessOutputBuffer.imageFormat = DRAW_FORMAT; + finalImageBuffer.imageFormat = DRAW_FORMAT; constexpr VkExtent3D imageExtent = {RENDER_EXTENTS.width, RENDER_EXTENTS.height, 1}; - postProcessOutputBuffer.imageExtent = imageExtent; + finalImageBuffer.imageExtent = imageExtent; VkImageUsageFlags usageFlags{}; + usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; - const VkImageCreateInfo imageCreateInfo = vk_helpers::imageCreateInfo(postProcessOutputBuffer.imageFormat, usageFlags, imageExtent); + const VkImageCreateInfo imageCreateInfo = vk_helpers::imageCreateInfo(finalImageBuffer.imageFormat, usageFlags, imageExtent); VmaAllocationCreateInfo imageAllocationInfo = {}; imageAllocationInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; imageAllocationInfo.requiredFlags = static_cast(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - vmaCreateImage(context->allocator, &imageCreateInfo, &imageAllocationInfo, &postProcessOutputBuffer.image, - &postProcessOutputBuffer.allocation, nullptr); + vmaCreateImage(context->allocator, &imageCreateInfo, &imageAllocationInfo, &finalImageBuffer.image, + &finalImageBuffer.allocation, nullptr); - VkImageViewCreateInfo rview_info = vk_helpers::imageviewCreateInfo(postProcessOutputBuffer.imageFormat, postProcessOutputBuffer.image, + VkImageViewCreateInfo rview_info = vk_helpers::imageviewCreateInfo(finalImageBuffer.imageFormat, finalImageBuffer.image, VK_IMAGE_ASPECT_COLOR_BIT); - VK_CHECK(vkCreateImageView(context->device, &rview_info, nullptr, &postProcessOutputBuffer.imageView)); + VK_CHECK(vkCreateImageView(context->device, &rview_info, nullptr, &finalImageBuffer.imageView)); } + +#if WILL_ENGINE_DEBUG + // Debug Output (Gizmos, Debug Draws, etc. Output here before combined w/ final image. Goes around normal pass stuff. Expects inputs to be jittered because to test against depth buffer, fragments need to be jittered cause depth buffer is jittered) + constexpr VkExtent3D imageExtent = {RENDER_EXTENTS.width, RENDER_EXTENTS.height, 1}; + VkImageUsageFlags usageFlags{}; + usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; + usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + const VkImageCreateInfo imageCreateInfo = vk_helpers::imageCreateInfo(DEBUG_FORMAT, usageFlags, imageExtent); + debugTarget = resourceManager->createImage(imageCreateInfo); +#endif } void Engine::setCsmSettings(const cascaded_shadows::CascadedShadowMapSettings& settings) diff --git a/src/core/engine.h b/src/core/engine.h index 78473738..e676beb5 100644 --- a/src/core/engine.h +++ b/src/core/engine.h @@ -5,7 +5,6 @@ #ifndef ENGINE_H #define ENGINE_H -#include #include #include @@ -28,12 +27,27 @@ #include "src/renderer/pipelines/shadows/ground_truth_ambient_occlusion/ambient_occlusion_types.h" +namespace will_engine::debug_renderer +{ +class DebugRenderer; +} + class ResourceManager; class ImmediateSubmitter; class VulkanContext; namespace will_engine { +namespace debug_highlight_pipeline +{ + class DebugHighlighter; +} + +namespace debug_pipeline +{ + class DebugCompositePipeline; +} + namespace ambient_occlusion { class GroundTruthAmbientOcclusionPipeline; @@ -135,7 +149,13 @@ class Engine void cleanup(); public: - [[nodiscard]] IHierarchical* createGameObject(Map* map, const std::string& name) const; + /** + * Creates a gameobject as a child of the map parameter + * @param map + * @param name + * @return + */ + [[nodiscard]] static IHierarchical* createGameObject(Map* map, const std::string& name); void addToBeginQueue(IHierarchical* obj); @@ -158,6 +178,13 @@ class Engine ResourceManager* resourceManager{nullptr}; AssetManager* assetManager{nullptr}; physics::Physics* physics{nullptr}; +#if WILL_ENGINE_DEBUG + debug_renderer::DebugRenderer* debugRenderer{nullptr}; + debug_highlight_pipeline::DebugHighlighter* debugHighlighter{nullptr}; + debug_pipeline::DebugCompositePipeline* debugPipeline{nullptr}; +#endif + // Might be used in imgui which can be active outside of debug build + IHierarchical* selectedItem{nullptr}; environment::Environment* environmentMap{nullptr}; @@ -206,10 +233,12 @@ class Engine bool bEnableDebugFrustumCullDraw{false}; int32_t deferredDebug{0}; bool bDrawTerrainLines{false}; - bool bPausePhysics{true}; + bool bEnablePhysics{true}; bool bDrawTransparents{true}; bool bEnableShadows{true}; bool bEnableContactShadows{true}; + bool bDrawDebugRendering{true}; + bool bDebugPhysics{true}; void hotReloadShaders() const; @@ -260,7 +289,12 @@ class Engine private: // Draw Resources AllocatedImage drawImage{}; - AllocatedImage depthImage{}; + /** + * Image view in this depth image is VK_IMAGE_ASPECT_DEPTH_BIT + */ + AllocatedImage depthStencilImage{}; + VkImageView depthImageView{VK_NULL_HANDLE}; + VkImageView stencilImageView{VK_NULL_HANDLE}; /** * 8.8.8 View Normals - 8 unused @@ -287,7 +321,12 @@ class Engine * A copy of the previous TAA Resolve Buffer */ AllocatedImage historyBuffer{}; - AllocatedImage postProcessOutputBuffer{}; + +#if WILL_ENGINE_DEBUG + AllocatedImage debugTarget{}; +#endif + + AllocatedImage finalImageBuffer{}; private: // Swapchain VkSwapchainKHR swapchain{}; diff --git a/src/core/game_object/components/mesh_renderer_component.cpp b/src/core/game_object/components/mesh_renderer_component.cpp index 997a3dde..68d0c951 100644 --- a/src/core/game_object/components/mesh_renderer_component.cpp +++ b/src/core/game_object/components/mesh_renderer_component.cpp @@ -41,6 +41,33 @@ void MeshRendererComponent::beginDestroy() releaseMesh(); } +void MeshRendererComponent::drawHighlight() +{ + if (!pRenderReference) { + return; + } + + std::optional> meshData = pRenderReference->getMeshData(meshIndex); + if (!meshData.has_value()) { return; } + + // for (const Primitive& primitive : meshData.value().get().primitives) { + // primitive.indexCount; + // uint32_t instanceCount = 1; + // primitive.firstIndex; + // primitive.vertexOffset; + // uint32_t firstInstance = 0; + // + // glm::mat4 pushModelMatrix = getModelMatrix(); + // + // // bind vertex and instance buffer from pRenderReference + // vkCmdBindVertexBuffers(cmd, 0, 1, &pRenderReference->getPositionVertexBuffer().buffer, &ZERO_DEVICE_SIZE); + // vkCmdBindIndexBuffer(cmd, pRenderReference->getIndexBuffer().buffer, 0, VK_INDEX_TYPE_UINT32); + // + // // Draw this mesh w/ vkCmdDrawIndexed w/ model matrix passed through push + // vkCmdDrawIndexed(cmd, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + // } +} + void MeshRendererComponent::serialize(ordered_json& j) { Component::serialize(j); @@ -145,7 +172,8 @@ void MeshRendererComponent::setOwner(IComponentContainer* owner) transformableOwner = dynamic_cast(owner); if (!transformableOwner) { - fmt::print("Attempted to attach a mesh renderer to an IComponentContainer that does not implement ITransformable. Model matrix will always be identity.\n"); + fmt::print( + "Attempted to attach a mesh renderer to an IComponentContainer that does not implement ITransformable. Model matrix will always be identity.\n"); } } } // namespace will_engine::components diff --git a/src/core/game_object/components/mesh_renderer_component.h b/src/core/game_object/components/mesh_renderer_component.h index c49305c2..1f0928b4 100644 --- a/src/core/game_object/components/mesh_renderer_component.h +++ b/src/core/game_object/components/mesh_renderer_component.h @@ -55,6 +55,9 @@ class MeshRendererComponent : public Component, public IRenderable void beginDestroy() override; +public: + void drawHighlight(); + public: // Serialization void serialize(ordered_json& j) override; @@ -79,6 +82,8 @@ class MeshRendererComponent : public Component, public IRenderable uint32_t getRenderReferenceId() const override { return pRenderReference ? pRenderReference->getId() : INDEX_NONE; } + IRenderReference* getRenderReference() const override { return pRenderReference; } + int32_t getMeshIndex() const override { return meshIndex; } void releaseMesh() override; diff --git a/src/core/game_object/renderable.h b/src/core/game_object/renderable.h index d4039852..f367dc56 100644 --- a/src/core/game_object/renderable.h +++ b/src/core/game_object/renderable.h @@ -21,6 +21,8 @@ class IRenderable [[nodiscard]] virtual uint32_t getRenderReferenceId() const = 0; + [[nodiscard]] virtual IRenderReference* getRenderReference() const = 0; + [[nodiscard]] virtual int32_t getMeshIndex() const = 0; [[nodiscard]] virtual bool& isVisible() = 0; diff --git a/src/core/time.cpp b/src/core/time.cpp index 84992bf0..c755bef5 100644 --- a/src/core/time.cpp +++ b/src/core/time.cpp @@ -21,10 +21,16 @@ void Time::update() // Breakpoint resume case if (deltaTime > 1000) { deltaTime = 333; } lastTime = last; + } float Time::getDeltaTime() const { return static_cast(deltaTime) / 1000.0f; } + +float Time::getTime() const +{ + return static_cast(lastTime) / 1000.0f; +} } diff --git a/src/core/time.h b/src/core/time.h index ff4f9e07..47073ef3 100644 --- a/src/core/time.h +++ b/src/core/time.h @@ -25,6 +25,8 @@ class Time [[nodiscard]] float getDeltaTime() const; + [[nodiscard]] float getTime() const; + private: uint64_t deltaTime = 0; uint64_t lastTime = 0; diff --git a/src/physics/debug/debug_renderer.cpp b/src/physics/debug/debug_renderer.cpp deleted file mode 100644 index 37ab9517..00000000 --- a/src/physics/debug/debug_renderer.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by William on 2024-12-26. -// - -#include "debug_renderer.h" diff --git a/src/physics/debug/debug_renderer.h b/src/physics/debug/debug_renderer.h deleted file mode 100644 index cd954f3f..00000000 --- a/src/physics/debug/debug_renderer.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by William on 2024-12-26. -// - -#ifndef DEBUG_RENDERER_H -#define DEBUG_RENDERER_H - -#include -#include - -namespace will_engine::physics -{ -class DebugRendererImpl final : public JPH::DebugRenderer -{ -public: - ~DebugRendererImpl() override; - - void DrawLine(JPH::RVec3Arg inFrom, JPH::RVec3Arg inTo, JPH::ColorArg inColor) override; - - void DrawTriangle(JPH::RVec3Arg inV1, JPH::RVec3Arg inV2, JPH::RVec3Arg inV3, JPH::ColorArg inColor, ECastShadow inCastShadow = ECastShadow::Off) override; - - Batch CreateTriangleBatch(const Triangle* inTriangles, int inTriangleCount) override; - - Batch CreateTriangleBatch(const Vertex* inVertices, int inVertexCount, const JPH::uint32* inIndices, int inIndexCount) override; - - void DrawGeometry(JPH::RMat44Arg inModelMatrix, const JPH::AABox& inWorldSpaceBounds, float inLODScaleSq, JPH::ColorArg inModelColor, const GeometryRef& inGeometry, ECullMode inCullMode, - ECastShadow inCastShadow, EDrawMode inDrawMode) override; - - void DrawText3D(JPH::RVec3Arg inPosition, const JPH::string_view& inString, JPH::ColorArg inColor, float inHeight) override; -}; -} - -#endif //DEBUG_RENDERER_H diff --git a/src/physics/debug/jolt_debug_renderer.cpp b/src/physics/debug/jolt_debug_renderer.cpp new file mode 100644 index 00000000..bcd871bb --- /dev/null +++ b/src/physics/debug/jolt_debug_renderer.cpp @@ -0,0 +1,105 @@ +// +// Created by William on 2024-12-26. +// + +#ifdef JPH_DEBUG_RENDERER + +#include "jolt_debug_renderer.h" + +#include "src/physics/physics_utils.h" +#include "../../renderer/pipelines/debug/debug_renderer.h" + + +will_engine::physics::JoltDebugRenderer::JoltDebugRenderer() +{ + Initialize(); +} + +will_engine::physics::JoltDebugRenderer::~JoltDebugRenderer() {} + +void will_engine::physics::JoltDebugRenderer::DrawLine(JPH::RVec3Arg inFrom, JPH::RVec3Arg inTo, const JPH::ColorArg inColor) +{ + debug_renderer::DebugRenderer::drawLine(PhysicsUtils::toGLM(inFrom), PhysicsUtils::toGLM(inTo), PhysicsUtils::toGLM(inColor)); +} + +void will_engine::physics::JoltDebugRenderer::DrawTriangle(JPH::RVec3Arg inV1, JPH::RVec3Arg inV2, JPH::RVec3Arg inV3, JPH::ColorArg inColor, + ECastShadow inCastShadow) +{ + debug_renderer::DebugRenderer::drawTriangle(PhysicsUtils::toGLM(inV1), PhysicsUtils::toGLM(inV2), PhysicsUtils::toGLM(inV3), + PhysicsUtils::toGLM(inColor)); +} + +JPH::DebugRenderer::Batch will_engine::physics::JoltDebugRenderer::CreateTriangleBatch(const Triangle* inTriangles, int inTriangleCount) +{ + // Copied from JPH::DebugRendererSimple + const auto batch = new BatchImpl; + if (inTriangles == nullptr || inTriangleCount == 0) + return batch; + + batch->mTriangles.assign(inTriangles, inTriangles + inTriangleCount); + return batch; +} + +JPH::DebugRenderer::Batch will_engine::physics::JoltDebugRenderer::CreateTriangleBatch(const Vertex* inVertices, int inVertexCount, + const JPH::uint32* inIndices, int inIndexCount) +{ + // Copied from JPH::DebugRendererSimple + const auto batch = new BatchImpl; + if (inVertices == nullptr || inVertexCount == 0 || inIndices == nullptr || inIndexCount == 0) + return batch; + + // Convert indexed triangle list to triangle list + batch->mTriangles.resize(inIndexCount / 3); + for (size_t t = 0; t < batch->mTriangles.size(); ++t) { + Triangle& triangle = batch->mTriangles[t]; + triangle.mV[0] = inVertices[inIndices[t * 3 + 0]]; + triangle.mV[1] = inVertices[inIndices[t * 3 + 1]]; + triangle.mV[2] = inVertices[inIndices[t * 3 + 2]]; + } + + return batch; +} + +void will_engine::physics::JoltDebugRenderer::DrawGeometry(JPH::RMat44Arg inModelMatrix, const JPH::AABox& inWorldSpaceBounds, float inLODScaleSq, + JPH::ColorArg inModelColor, const GeometryRef& inGeometry, ECullMode inCullMode, + ECastShadow inCastShadow, EDrawMode inDrawMode) +{ + // cull mode is always ignored (never cull) + // cast shadow is always ignored (never cast shadows) + // draw mode is always ignored (always wireframe) + + // Copied from JPH::DebugRendererSimple + // Figure out which LOD to use (default to LOD 0) + const LOD* lod = inGeometry->mLODs.data(); + if (mCameraPosSet) + lod = &inGeometry->GetLOD(JPH::Vec3(mCameraPos), inWorldSpaceBounds, inLODScaleSq); + + // Draw the batch + const BatchImpl* batch = static_cast(lod->mTriangleBatch.GetPtr()); + for (const Triangle& triangle : batch->mTriangles) { + const JPH::RVec3 v0 = inModelMatrix * JPH::Vec3(triangle.mV[0].mPosition); + const JPH::RVec3 v1 = inModelMatrix * JPH::Vec3(triangle.mV[1].mPosition); + const JPH::RVec3 v2 = inModelMatrix * JPH::Vec3(triangle.mV[2].mPosition); + const JPH::Color color = inModelColor * triangle.mV[0].mColor; + + switch (inDrawMode) { + case EDrawMode::Wireframe: + DrawLine(v0, v1, color); + DrawLine(v1, v2, color); + DrawLine(v2, v0, color); + break; + + case EDrawMode::Solid: + DrawTriangle(v0, v1, v2, color, inCastShadow); + break; + } + } +} + +void will_engine::physics::JoltDebugRenderer::DrawText3D(JPH::RVec3Arg inPosition, const JPH::string_view& inString, JPH::ColorArg inColor, + float inHeight) +{ + // Do not implement this +} + +#endif // JPH_DEBUG_RENDERER diff --git a/src/physics/debug/jolt_debug_renderer.h b/src/physics/debug/jolt_debug_renderer.h new file mode 100644 index 00000000..b08e1430 --- /dev/null +++ b/src/physics/debug/jolt_debug_renderer.h @@ -0,0 +1,63 @@ +// +// Created by William on 2024-12-26. +// + +#ifndef JOLT_DEBUG_RENDERER_H +#define JOLT_DEBUG_RENDERER_H + +#include +#include + +#ifndef JPH_DEBUG_RENDERER + #error This file should only be included when JPH_DEBUG_RENDERER is defined +#endif // !JPH_DEBUG_RENDERER + +namespace will_engine::debug_renderer +{ +class DebugRenderer; +} + +namespace will_engine::physics +{ +class JoltDebugRenderer final : public JPH::DebugRenderer +{ +public: + JoltDebugRenderer(); + + ~JoltDebugRenderer() override; + + void DrawLine(JPH::RVec3Arg inFrom, JPH::RVec3Arg inTo, JPH::ColorArg inColor) override; + + void DrawTriangle(JPH::RVec3Arg inV1, JPH::RVec3Arg inV2, JPH::RVec3Arg inV3, JPH::ColorArg inColor, ECastShadow inCastShadow) override; + + Batch CreateTriangleBatch(const Triangle* inTriangles, int inTriangleCount) override; + + Batch CreateTriangleBatch(const Vertex* inVertices, int inVertexCount, const JPH::uint32* inIndices, int inIndexCount) override; + + void DrawGeometry(JPH::RMat44Arg inModelMatrix, const JPH::AABox& inWorldSpaceBounds, float inLODScaleSq, JPH::ColorArg inModelColor, + const GeometryRef& inGeometry, ECullMode inCullMode, + ECastShadow inCastShadow, EDrawMode inDrawMode) override; + + void DrawText3D(JPH::RVec3Arg inPosition, const JPH::string_view& inString, JPH::ColorArg inColor, float inHeight) override; + + class BatchImpl final : public JPH::RefTargetVirtual + { + public: + JPH_OVERRIDE_NEW_DELETE + + virtual void AddRef() override { ++mRefCount; } + virtual void Release() override { if (--mRefCount == 0) delete this; } + + JPH::Array mTriangles; + + private: + std::atomic mRefCount = 0; + }; + + /// Last provided camera position + JPH::RVec3 mCameraPos; + bool mCameraPosSet = false; +}; +} + +#endif //JOLT_DEBUG_RENDERER_H diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 63b6982b..91c53c50 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -47,6 +47,10 @@ Physics::Physics() // Create physics system physicsSystem = new JPH::PhysicsSystem(); +#ifdef JPH_DEBUG_RENDERER + joltDebugRenderer = new JoltDebugRenderer(); + joltDebugDrawFilter = new JoltDebugDrawFilter(); +#endif physicsSystem->Init( MAX_BODIES, NUM_BODY_MUTEXES, @@ -261,7 +265,7 @@ JPH::BodyID Physics::setupRigidbody(IPhysicsBody* physicsBody, const JPH::EShape shape = getUnitCapsuleShape(); break; } - shape = new JPH::CapsuleShape(shapeParams.y, shapeParams.z); + shape = new JPH::CapsuleShape(shapeParams.y, shapeParams.x); break; case JPH::EShapeSubType::Cylinder: if (shapeParams == UNIT_CYLINDER) { @@ -341,6 +345,11 @@ void Physics::releaseRigidbody(IPhysicsBody* physicsBody) physicsSystem->GetBodyInterface().DestroyBody(bodyId); physicsObjects.erase(bodyId); physicsBody->setPhysicsBodyId(JPH::BodyID(JPH::BodyID::cMaxBodyIndex)); + +#ifdef JPH_DEBUG_RENDERER + joltDebugDrawFilter->RemoveBody(bodyId); +#endif // JPH_DEBUG_RENDERER + } void Physics::setPositionAndRotation(const JPH::BodyID bodyId, const glm::vec3 position, const glm::quat rotation, const bool activate) const @@ -411,6 +420,14 @@ void Physics::setMotionType(const IPhysicsBody* body, const JPH::EMotionType mot physicsSystem->GetBodyInterface().SetMotionType(body->getPhysicsBodyId(), motionType, activation); } +void Physics::drawDebug() +{ +#ifdef JPH_DEBUG_RENDERER + constexpr JPH::BodyManager::DrawSettings drawSettings{}; + physicsSystem->DrawBodies(drawSettings, joltDebugRenderer, joltDebugDrawFilter); +#endif +} + PhysicsProperties Physics::serializeProperties(const IPhysicsBody* physicsBody) const { if (physicsBody == nullptr || physicsBody->getPhysicsBodyId().GetIndex() == JPH::BodyID::cMaxBodyIndex) { @@ -472,4 +489,18 @@ bool Physics::deserializeProperties(IPhysicsBody* physicsBody, const PhysicsProp auto bodyId = setupRigidbody(physicsBody, properties.shapeType, properties.shapeParams, static_cast(properties.motionType), properties.layer); return bodyId.GetIndex() != JPH::BodyID::cMaxBodyIndex; } + +void Physics::drawDebug(const JPH::BodyID bodyId) const +{ +#ifdef JPH_DEBUG_RENDERER + joltDebugDrawFilter->AddBody(bodyId); +#endif // JPH_DEBUG_RENDERER +} + +void Physics::stopDrawDebug(const JPH::BodyID bodyId) const +{ +#ifdef JPH_DEBUG_RENDERER + joltDebugDrawFilter->RemoveBody(bodyId); +#endif // JPH_DEBUG_RENDERER +} } diff --git a/src/physics/physics.h b/src/physics/physics.h index a8db72f8..4a4d04a0 100644 --- a/src/physics/physics.h +++ b/src/physics/physics.h @@ -18,6 +18,9 @@ #include "physics_types.h" #include "physics_body.h" +#ifdef JPH_DEBUG_RENDERER +#include "debug/jolt_debug_renderer.h" +#endif // JPH_DEBUG_RENDERER class GameObject; @@ -72,9 +75,11 @@ class Physics PhysicsObject* getPhysicsObject(JPH::BodyID bodyId); public: - JPH::BodyID setupRigidbody(IPhysicsBody* physicsBody, JPH::EShapeSubType shapeType, glm::vec3 shapeParams, JPH::EMotionType motion, JPH::ObjectLayer layer); + JPH::BodyID setupRigidbody(IPhysicsBody* physicsBody, JPH::EShapeSubType shapeType, glm::vec3 shapeParams, JPH::EMotionType motion, + JPH::ObjectLayer layer); - JPH::BodyID setupRigidbody(IPhysicsBody* physicsBody, JPH::HeightFieldShapeSettings& heightFieldShapeSettings, JPH::EMotionType motion, JPH::ObjectLayer layer); + JPH::BodyID setupRigidbody(IPhysicsBody* physicsBody, JPH::HeightFieldShapeSettings& heightFieldShapeSettings, JPH::EMotionType motion, + JPH::ObjectLayer layer); void releaseRigidbody(IPhysicsBody* physicsBody); @@ -96,10 +101,13 @@ class Physics void setMotionType(const IPhysicsBody* body, JPH::EMotionType motionType, JPH::EActivation activation) const; + void drawDebug(); + public: // Serialization PhysicsProperties serializeProperties(const IPhysicsBody* physicsBody) const; bool deserializeProperties(IPhysicsBody* physicsBody, const PhysicsProperties& properties); + private: // Core systems JPH::PhysicsSystem* physicsSystem = nullptr; @@ -128,6 +136,54 @@ class Physics JPH::ShapeRefC unitSphereShape = nullptr; JPH::ShapeRefC unitCapsuleShape = nullptr; JPH::ShapeRefC unitCylinderShape = nullptr; + + +public: // Debug + void drawDebug(JPH::BodyID bodyId) const; + void stopDrawDebug(JPH::BodyID bodyId) const; + +private: // Debug +#ifdef JPH_DEBUG_RENDERER + class JoltDebugDrawFilter final : public JPH::BodyDrawFilter + { + public: + ~JoltDebugDrawFilter() override = default; + + bool ShouldDraw(const JPH::Body& inBody) const override + { + return !bodiesToDraw.empty() && std::ranges::find(bodiesToDraw, inBody.GetID()) != bodiesToDraw.end(); + } + + void AddBody(const JPH::BodyID bodyId) + { + if (std::ranges::find(bodiesToDraw, bodyId) == bodiesToDraw.end()) { + bodiesToDraw.push_back(bodyId); + } + } + + void RemoveBody(const JPH::BodyID bodyId) + { + const auto it = std::ranges::find(bodiesToDraw, bodyId); + if (it != bodiesToDraw.end()) { + bodiesToDraw.erase(it); + } + } + + void Clear() + { + bodiesToDraw.clear(); + } + + private: + std::vector bodiesToDraw; + }; + + + JoltDebugDrawFilter* joltDebugDrawFilter{nullptr}; + JoltDebugRenderer* joltDebugRenderer{nullptr}; +#endif + +public: }; } diff --git a/src/physics/physics_utils.cpp b/src/physics/physics_utils.cpp index c4521d72..fc2bb843 100644 --- a/src/physics/physics_utils.cpp +++ b/src/physics/physics_utils.cpp @@ -26,6 +26,11 @@ glm::mat4 will_engine::physics::PhysicsUtils::toGLM(const JPH::Mat44& mat) }; } +glm::vec3 will_engine::physics::PhysicsUtils::toGLM(JPH::ColorArg inColor) +{ + return {inColor.r, inColor.g, inColor.b}; +} + JPH::Vec3 will_engine::physics::PhysicsUtils::toJolt(const glm::vec3& v) { return {v.x, v.y, v.z}; diff --git a/src/physics/physics_utils.h b/src/physics/physics_utils.h index aebee8c8..0da10b06 100644 --- a/src/physics/physics_utils.h +++ b/src/physics/physics_utils.h @@ -24,6 +24,8 @@ class PhysicsUtils static glm::mat4 toGLM(const JPH::Mat44& mat); + static glm::vec3 toGLM(JPH::ColorArg inColor); + static JPH::Vec3 toJolt(const glm::vec3& v); static JPH::Quat toJolt(const glm::quat& q); diff --git a/src/renderer/assets/asset_manager.cpp b/src/renderer/assets/asset_manager.cpp index d36c38d0..8d537f5a 100644 --- a/src/renderer/assets/asset_manager.cpp +++ b/src/renderer/assets/asset_manager.cpp @@ -15,14 +15,14 @@ will_engine::AssetManager::~AssetManager() void will_engine::AssetManager::scanForAll() { + fmt::print("Scanning for .willmodel and .willtexture files\n"); + scanForRenderObjects(); scanForTextures(); } void will_engine::AssetManager::scanForTextures() { - fmt::print("Scanning for .willtexture files\n"); - const std::vector willTextures = file::findWillFiles(relative(std::filesystem::current_path() / "assets"), ".willtexture"); textures.reserve(willTextures.size()); for (std::filesystem::path willTexture : willTextures) { @@ -38,8 +38,6 @@ void will_engine::AssetManager::scanForTextures() void will_engine::AssetManager::scanForRenderObjects() { - fmt::print("Scanning for .willmodel files\n"); - const std::vector willModels = file::findWillFiles(relative(std::filesystem::current_path() / "assets"), ".willmodel"); renderObjects.reserve(willModels.size()); for (std::filesystem::path willModel : willModels) { diff --git a/src/renderer/assets/render_object/render_object.cpp b/src/renderer/assets/render_object/render_object.cpp index 9eb2e981..2c7228d3 100644 --- a/src/renderer/assets/render_object/render_object.cpp +++ b/src/renderer/assets/render_object/render_object.cpp @@ -62,7 +62,7 @@ void RenderObject::update(VkCommandBuffer cmd, const int32_t currentFrameOverlap renderable->setRenderFramesToUpdate(renderable->getRenderFramesToUpdate() - 1); - vk_helpers::synchronizeUniform(cmd, currentFrameModelMatrix, VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, + vk_helpers::uniformBarrier(cmd, currentFrameModelMatrix, VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_WRITE_BIT, VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, VK_ACCESS_2_UNIFORM_READ_BIT); } } @@ -78,7 +78,7 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame // Recreate the primitive buffer if needed size_t latestPrimitiveBufferSize = currentMaxPrimitiveCount * sizeof(PrimitiveData); if (currentPrimitiveBuffer.info.size != latestPrimitiveBufferSize) { - resourceManager.destroyBuffer(currentPrimitiveBuffer); + resourceManager.destroy(currentPrimitiveBuffer); currentPrimitiveBuffer = resourceManager.createHostRandomBuffer(latestPrimitiveBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); @@ -102,11 +102,10 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame *pPrimitiveData = pair.second; } - // vk_helpers::synchronizeUniform(cmd, currentPrimitiveBuffer, VK_PIPELINE_STAGE_2_HOST_BIT - // , VK_ACCESS_2_HOST_WRITE_BIT - // , VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT | - // VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT - // , VK_ACCESS_2_UNIFORM_READ_BIT); + vk_helpers::uniformBarrier(cmd, currentPrimitiveBuffer, VK_PIPELINE_STAGE_2_HOST_BIT + , VK_ACCESS_2_HOST_WRITE_BIT + , VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT + , VK_ACCESS_2_UNIFORM_READ_BIT); } AllocatedBuffer& currentInstanceBuffer = modelMatrixBuffers[currentFrameOverlap]; @@ -115,7 +114,7 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame // sizes don't match, need to recreate the buffer size_t latestInstanceBufferSize = currentMaxInstanceCount * sizeof(InstanceData); if (currentInstanceBuffer.info.size != latestInstanceBufferSize) { - resourceManager.destroyBuffer(currentInstanceBuffer); + resourceManager.destroy(currentInstanceBuffer); currentInstanceBuffer = resourceManager.createHostRandomBuffer(latestInstanceBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); @@ -145,9 +144,9 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame } AllocatedBuffer& currentOpaqueDrawIndirectBuffer = opaqueDrawIndirectBuffers[currentFrameOverlap]; - resourceManager.destroyBuffer(currentOpaqueDrawIndirectBuffer); + resourceManager.destroy(currentOpaqueDrawIndirectBuffer); if (!opaqueDrawCommands.empty()) { - resourceManager.destroyBuffer(currentOpaqueDrawIndirectBuffer); + resourceManager.destroy(currentOpaqueDrawIndirectBuffer); AllocatedBuffer indirectStaging = resourceManager.createStagingBuffer(opaqueDrawCommands.size() * sizeof(VkDrawIndexedIndirectCommand)); memcpy(indirectStaging.info.pMappedData, opaqueDrawCommands.data(), opaqueDrawCommands.size() * sizeof(VkDrawIndexedIndirectCommand)); currentOpaqueDrawIndirectBuffer = resourceManager.createDeviceBuffer(opaqueDrawCommands.size() * sizeof(VkDrawIndexedIndirectCommand), @@ -155,7 +154,7 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame vk_helpers::copyBuffer(cmd, indirectStaging, 0, currentOpaqueDrawIndirectBuffer, 0, opaqueDrawCommands.size() * sizeof(VkDrawIndexedIndirectCommand)); - resourceManager.destroyBuffer(indirectStaging); + resourceManager.destroy(indirectStaging); const FrustumCullingBuffers cullingAddresses{ .meshBoundsBuffer = resourceManager.getBufferAddress(meshBoundsBuffer), @@ -168,11 +167,11 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame AllocatedBuffer stagingCullingAddressesBuffer = resourceManager.createStagingBuffer(sizeof(FrustumCullingBuffers)); memcpy(stagingCullingAddressesBuffer.info.pMappedData, &cullingAddresses, sizeof(FrustumCullingBuffers)); vk_helpers::copyBuffer(cmd, stagingCullingAddressesBuffer, 0, currentCullingAddressBuffers, 0, sizeof(FrustumCullingBuffers)); - resourceManager.destroyBuffer(stagingCullingAddressesBuffer); + resourceManager.destroy(stagingCullingAddressesBuffer); } AllocatedBuffer& currentTransparentDrawIndirectBuffer = transparentDrawIndirectBuffers[currentFrameOverlap]; - resourceManager.destroyBuffer(currentTransparentDrawIndirectBuffer); + resourceManager.destroy(currentTransparentDrawIndirectBuffer); if (!transparentDrawCommands.empty()) { AllocatedBuffer indirectStaging = resourceManager.createStagingBuffer(transparentDrawCommands.size() * sizeof(VkDrawIndexedIndirectCommand)); @@ -184,7 +183,7 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame vk_helpers::copyBuffer(cmd, indirectStaging, 0, currentTransparentDrawIndirectBuffer, 0, transparentDrawCommands.size() * sizeof(VkDrawIndexedIndirectCommand)); - resourceManager.destroyBuffer(indirectStaging); + resourceManager.destroy(indirectStaging); const FrustumCullingBuffers cullingAddresses{ .meshBoundsBuffer = resourceManager.getBufferAddress(meshBoundsBuffer), @@ -197,7 +196,7 @@ bool RenderObject::updateBuffers(VkCommandBuffer cmd, const int32_t currentFrame AllocatedBuffer stagingCullingAddressesBuffer = resourceManager.createStagingBuffer(sizeof(FrustumCullingBuffers)); memcpy(stagingCullingAddressesBuffer.info.pMappedData, &cullingAddresses, sizeof(FrustumCullingBuffers)); vk_helpers::copyBuffer(cmd, stagingCullingAddressesBuffer, 0, currentCullingAddressBuffers, 0, sizeof(FrustumCullingBuffers)); - resourceManager.destroyBuffer(stagingCullingAddressesBuffer); + resourceManager.destroy(stagingCullingAddressesBuffer); } bufferFramesToUpdate--; @@ -336,8 +335,15 @@ bool RenderObject::releaseInstanceIndex(IRenderable* renderable) return true; } +std::optional > RenderObject::getMeshData(const int32_t meshIndex) +{ + if (meshIndex < 0 || meshIndex >= meshes.size()) { return std::nullopt; } + return meshes[meshIndex]; +} + bool RenderObject::parseGltf(const std::filesystem::path& gltfFilepath, std::vector& materials, - std::vector& vertexPositions, std::vector& vertexProperties, std::vector& indices) + std::vector& vertexPositions, std::vector& vertexProperties, + std::vector& indices) { auto start = std::chrono::system_clock::now(); @@ -686,7 +692,7 @@ void RenderObject::load() } uint64_t boundingSphereBufferSize = sizeof(BoundingSphere) * boundingSpheres.size(); - AllocatedBuffer meshBoundsStaging = resourceManager.createStagingBuffer(boundingSphereBufferSize); + const AllocatedBuffer meshBoundsStaging = resourceManager.createStagingBuffer(boundingSphereBufferSize); memcpy(meshBoundsStaging.info.pMappedData, boundingSpheres.data(), boundingSphereBufferSize); meshBoundsBuffer = resourceManager.createDeviceBuffer(boundingSphereBufferSize); @@ -703,7 +709,7 @@ void RenderObject::load() // Be careful, this destroys a copy of the staging buffer. Not an issue since it deletes the buffer in GPU memory. // Will be dangerous if you attempt to hold onto the staging buffers outside of this load function for (BufferCopyInfo bufferCopy : bufferCopies) { - resourceManager.destroyBufferImmediate(bufferCopy.src); + resourceManager.destroyImmediate(bufferCopy.src); } bIsLoaded = true; @@ -730,7 +736,7 @@ void RenderObject::unload() continue; } - resourceManager.destroyImage(image); + resourceManager.destroy(image); } for (auto& sampler : samplers) { @@ -739,30 +745,30 @@ void RenderObject::unload() continue; } - resourceManager.destroySampler(sampler); + resourceManager.destroy(sampler); } - resourceManager.destroyBuffer(vertexPositionBuffer); - resourceManager.destroyBuffer(vertexPropertyBuffer); - resourceManager.destroyBuffer(indexBuffer); + resourceManager.destroy(vertexPositionBuffer); + resourceManager.destroy(vertexPropertyBuffer); + resourceManager.destroy(indexBuffer); - resourceManager.destroyBuffer(materialBuffer); + resourceManager.destroy(materialBuffer); - resourceManager.destroyBuffer(meshBoundsBuffer); + resourceManager.destroy(meshBoundsBuffer); for (int i = 0; i < FRAME_OVERLAP; ++i) { - resourceManager.destroyBuffer(opaqueDrawIndirectBuffers[i]); - resourceManager.destroyBuffer(transparentDrawIndirectBuffers[i]); - resourceManager.destroyBuffer(addressBuffers[i]); - resourceManager.destroyBuffer(primitiveDataBuffers[i]); - resourceManager.destroyBuffer(modelMatrixBuffers[i]); - resourceManager.destroyBuffer(opaqueCullingAddressBuffers[i]); - resourceManager.destroyBuffer(transparentCullingAddressBuffers[i]); - } - - resourceManager.destroyDescriptorBuffer(addressesDescriptorBuffer); - resourceManager.destroyDescriptorBuffer(frustumCullingDescriptorBuffer); - resourceManager.destroyDescriptorBuffer(textureDescriptorBuffer); + resourceManager.destroy(opaqueDrawIndirectBuffers[i]); + resourceManager.destroy(transparentDrawIndirectBuffers[i]); + resourceManager.destroy(addressBuffers[i]); + resourceManager.destroy(primitiveDataBuffers[i]); + resourceManager.destroy(modelMatrixBuffers[i]); + resourceManager.destroy(opaqueCullingAddressBuffers[i]); + resourceManager.destroy(transparentCullingAddressBuffers[i]); + } + + resourceManager.destroy(addressesDescriptorBuffer); + resourceManager.destroy(frustumCullingDescriptorBuffer); + resourceManager.destroy(textureDescriptorBuffer); opaqueDrawCommands.clear(); transparentDrawCommands.clear(); diff --git a/src/renderer/assets/render_object/render_object.h b/src/renderer/assets/render_object/render_object.h index 9d61df34..0d679430 100644 --- a/src/renderer/assets/render_object/render_object.h +++ b/src/renderer/assets/render_object/render_object.h @@ -99,6 +99,8 @@ class RenderObject final : public IRenderReference bool releaseInstanceIndex(IRenderable* renderable) override; + std::optional> getMeshData(int32_t meshIndex) override;; + private: // IRenderReference /** * Hash of the file path @@ -115,9 +117,9 @@ class RenderObject final : public IRenderReference [[nodiscard]] const DescriptorBufferUniform& getAddressesDescriptorBuffer() const { return addressesDescriptorBuffer; } [[nodiscard]] const DescriptorBufferSampler& getTextureDescriptorBuffer() const { return textureDescriptorBuffer; } [[nodiscard]] const DescriptorBufferUniform& getFrustumCullingAddressesDescriptorBuffer() { return frustumCullingDescriptorBuffer; } - [[nodiscard]] const AllocatedBuffer& getPositionVertexBuffer() const { return vertexPositionBuffer; } - [[nodiscard]] const AllocatedBuffer& getPropertyVertexBuffer() const { return vertexPropertyBuffer; } - [[nodiscard]] const AllocatedBuffer& getIndexBuffer() const { return indexBuffer; } + [[nodiscard]] const AllocatedBuffer& getPositionVertexBuffer() const override { return vertexPositionBuffer; } + [[nodiscard]] const AllocatedBuffer& getPropertyVertexBuffer() const override { return vertexPropertyBuffer; } + [[nodiscard]] const AllocatedBuffer& getIndexBuffer() const override { return indexBuffer; } [[nodiscard]] const AllocatedBuffer& getOpaqueIndirectBuffer(const int32_t currentFrameOverlap) const { diff --git a/src/renderer/assets/render_object/render_reference.h b/src/renderer/assets/render_object/render_reference.h index d5268533..2e04fc4b 100644 --- a/src/renderer/assets/render_object/render_reference.h +++ b/src/renderer/assets/render_object/render_reference.h @@ -5,8 +5,13 @@ #ifndef RENDER_REFERENCE_H #define RENDER_REFERENCE_H +#include + #include +#include "src/renderer/vk_types.h" +#include "render_object_types.h" + namespace will_engine { class IRenderable; @@ -26,6 +31,14 @@ class IRenderReference [[nodiscard]] virtual uint32_t getId() const = 0; virtual bool releaseInstanceIndex(IRenderable* renderable) = 0; + + virtual std::optional> getMeshData(int32_t meshIndex) = 0; + + virtual const AllocatedBuffer& getPositionVertexBuffer() const = 0; + + virtual const AllocatedBuffer& getPropertyVertexBuffer() const = 0; + + virtual const AllocatedBuffer& getIndexBuffer() const = 0; }; } diff --git a/src/renderer/assets/texture/texture_resource.cpp b/src/renderer/assets/texture/texture_resource.cpp index e1cec583..8453a97e 100644 --- a/src/renderer/assets/texture/texture_resource.cpp +++ b/src/renderer/assets/texture/texture_resource.cpp @@ -48,6 +48,6 @@ TextureResource::TextureResource(ResourceManager& resourceManager, const std::fi TextureResource::~TextureResource() { // todo: deferred texture destruction for multi-buffer modification - resourceManager.destroyImage(image); + resourceManager.destroy(image); } } // will_engine diff --git a/src/renderer/environment/environment.cpp b/src/renderer/environment/environment.cpp index a76bfe8c..24105281 100644 --- a/src/renderer/environment/environment.cpp +++ b/src/renderer/environment/environment.cpp @@ -98,7 +98,7 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana computePipelineCreateInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; equiToCubemapPipeline = resourceManager.createComputePipeline(computePipelineCreateInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } // Cubemap -> Diff Pipeline @@ -136,7 +136,7 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana computePipelineCreateInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; cubemapToDiffusePipeline = resourceManager.createComputePipeline(computePipelineCreateInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } // Cubemap -> Spec Pipeline @@ -174,7 +174,7 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana computePipelineCreateInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; cubemapToSpecularPipeline = resourceManager.createComputePipeline(computePipelineCreateInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } // LUT Generation @@ -207,7 +207,7 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana computePipelineCreateInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; lutPipeline = resourceManager.createComputePipeline(computePipelineCreateInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } @@ -233,7 +233,7 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana resourceManager.setupDescriptorBufferSampler(lutDescriptorBuffer, descriptor, 0); immediate.submit([&](VkCommandBuffer cmd) { - vk_helpers::transitionImage(cmd, lutImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, lutImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, lutPipeline); @@ -253,7 +253,7 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana constexpr uint32_t z_disp = 1; vkCmdDispatch(cmd, xDisp, yDisp, z_disp); - vk_helpers::transitionImage(cmd, lutImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, lutImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); }); } @@ -273,37 +273,37 @@ will_engine::environment::Environment::Environment(ResourceManager& resourceMana will_engine::environment::Environment::~Environment() { - resourceManager.destroyPipelineLayout(equiToCubemapPipelineLayout); - resourceManager.destroyPipelineLayout(cubemapToDiffusePipelineLayout); - resourceManager.destroyPipelineLayout(cubemapToSpecularPipelineLayout); - resourceManager.destroyPipelineLayout(lutPipelineLayout); - resourceManager.destroyPipeline(equiToCubemapPipeline); - resourceManager.destroyPipeline(cubemapToDiffusePipeline); - resourceManager.destroyPipeline(cubemapToSpecularPipeline); - resourceManager.destroyPipeline(lutPipeline); + resourceManager.destroy(equiToCubemapPipelineLayout); + resourceManager.destroy(cubemapToDiffusePipelineLayout); + resourceManager.destroy(cubemapToSpecularPipelineLayout); + resourceManager.destroy(lutPipelineLayout); + resourceManager.destroy(equiToCubemapPipeline); + resourceManager.destroy(cubemapToDiffusePipeline); + resourceManager.destroy(cubemapToSpecularPipeline); + resourceManager.destroy(lutPipeline); - resourceManager.destroySampler(sampler); + resourceManager.destroy(sampler); - resourceManager.destroyDescriptorBuffer(cubemapStorageDescriptorBuffer); - resourceManager.destroyDescriptorBuffer(cubemapDescriptorBuffer); - resourceManager.destroyDescriptorBuffer(equiImageDescriptorBuffer); - resourceManager.destroyDescriptorBuffer(diffSpecMapDescriptorBuffer); - resourceManager.destroyDescriptorBuffer(lutDescriptorBuffer); + resourceManager.destroy(cubemapStorageDescriptorBuffer); + resourceManager.destroy(cubemapDescriptorBuffer); + resourceManager.destroy(equiImageDescriptorBuffer); + resourceManager.destroy(diffSpecMapDescriptorBuffer); + resourceManager.destroy(lutDescriptorBuffer); - resourceManager.destroyImage(lutImage); + resourceManager.destroy(lutImage); lutImage = {}; for (EnvironmentMapData& envMap : environmentMaps) { - resourceManager.destroyImage(envMap.cubemapImage); - resourceManager.destroyImage(envMap.specDiffCubemap); + resourceManager.destroy(envMap.cubemapImage); + resourceManager.destroy(envMap.specDiffCubemap); } - resourceManager.destroyDescriptorSetLayout(equiImageLayout); - resourceManager.destroyDescriptorSetLayout(cubemapStorageLayout); - resourceManager.destroyDescriptorSetLayout(cubemapSamplerLayout); - resourceManager.destroyDescriptorSetLayout(lutLayout); - resourceManager.destroyDescriptorSetLayout(environmentIBLLayout); + resourceManager.destroy(equiImageLayout); + resourceManager.destroy(cubemapStorageLayout); + resourceManager.destroy(cubemapSamplerLayout); + resourceManager.destroy(lutLayout); + resourceManager.destroy(environmentIBLLayout); } void will_engine::environment::Environment::loadEnvironment(const char* name, const char* path, int32_t environmentMapIndex) @@ -366,7 +366,7 @@ void will_engine::environment::Environment::loadEnvironment(const char* name, co immediate.submit([&](VkCommandBuffer cmd) { - vk_helpers::transitionImage(cmd, newEnvMapData.cubemapImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, newEnvMapData.cubemapImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, equiToCubemapPipeline); @@ -389,7 +389,7 @@ void will_engine::environment::Environment::loadEnvironment(const char* name, co // can safely destroy the cubemap image view in the storage buffer - resourceManager.destroyImage(equiImage); + resourceManager.destroy(equiImage); cubemapStorageDescriptorBuffer.freeDescriptorBufferIndex(cubemapIndex); equiImageDescriptorBuffer.freeDescriptorBufferIndex(equipIndex); @@ -432,7 +432,7 @@ void will_engine::environment::Environment::loadEnvironment(const char* name, co } immediate.submit([&](VkCommandBuffer cmd) { - vk_helpers::transitionImage(cmd, specDiffCubemap.allocatedImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, specDiffCubemap.allocatedImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); VkDescriptorBufferBindingInfoEXT descriptorBufferBindingInfo[2]; @@ -497,13 +497,13 @@ void will_engine::environment::Environment::loadEnvironment(const char* name, co } - vk_helpers::transitionImage(cmd, specDiffCubemap.allocatedImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, specDiffCubemap.allocatedImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); }); // can safely destroy all the storage mip level image views since we don't plan on writing to them anymore for (CubemapImageView specDiffView : specDiffCubemap.cubemapImageViews) { - resourceManager.destroyImageView(specDiffView.imageView); + resourceManager.destroy(specDiffView.imageView); } specDiffCubemap.cubemapImageViews.clear(); cubemapStorageDescriptorBuffer.freeAllDescriptorBufferIndices(); diff --git a/src/renderer/imgui_wrapper.cpp b/src/renderer/imgui_wrapper.cpp index a8cc20c5..981e6d3a 100644 --- a/src/renderer/imgui_wrapper.cpp +++ b/src/renderer/imgui_wrapper.cpp @@ -12,6 +12,7 @@ #include "environment/environment.h" +#include "pipelines/debug/debug_highlighter.h" #include "pipelines/post/post_process/post_process_pipeline_types.h" #include "pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.h" #include "pipelines/shadows/ground_truth_ambient_occlusion/ambient_occlusion_types.h" @@ -21,6 +22,7 @@ #include "src/core/camera/free_camera.h" #include "src/core/game_object/renderable.h" #include "src/core/scene/serializer.h" +#include "src/physics/physics.h" #include "src/util/file.h" #include "src/util/math_utils.h" @@ -232,6 +234,8 @@ void ImguiWrapper::imguiInterface(Engine* engine) ImGui::Checkbox("Enable Shadows", &engine->bEnableShadows); ImGui::Checkbox("Enable Contact Shadows", &engine->bEnableContactShadows); ImGui::Checkbox("Enable Transparent Primitives", &engine->bDrawTransparents); + ImGui::Checkbox("Disable Physics", &engine->bEnablePhysics); + ImGui::Checkbox("Enable Physics Debug", &engine->bDebugPhysics); ImGui::DragInt("Shadows PCF Level", &engine->csmSettings.pcfLevel, 2, 1, 5); @@ -276,6 +280,11 @@ void ImguiWrapper::imguiInterface(Engine* engine) ImGui::Unindent(); } + if (ImGui::Button("Hard-Reset All Camera Settings")) { + delete engine->camera; + engine->camera = new FreeCamera(); + } + ImGui::EndTabItem(); } @@ -614,8 +623,6 @@ void ImguiWrapper::imguiInterface(Engine* engine) ImGui::Separator(); - ImGui::Checkbox("Disable Physics", &engine->bPausePhysics); - ImGui::Text("Deferred Debug"); const char* deferredDebugOptions[]{ "None", "Depth", "Velocity", "Albedo", "Normal", "PBR", "Shadows", "Cascade Level", "nDotL", "AO", "Contact Shadows" @@ -632,8 +639,7 @@ void ImguiWrapper::imguiInterface(Engine* engine) if (ImGui::Button("Save Draw Image")) { if (file::getOrCreateDirectory(file::imagesSavePath)) { const std::filesystem::path path = file::imagesSavePath / "drawImage.png"; - vk_helpers::saveImageRGBA16SFLOAT(*engine->resourceManager, *engine->immediate, engine->drawImage, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, path.string().c_str()); + vk_helpers::saveImage(*engine->resourceManager, *engine->immediate, engine->drawImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, vk_helpers::ImageFormat::RGBA16F, path.string()); } else { fmt::print(" Failed to find/create image save path directory"); @@ -650,7 +656,7 @@ void ImguiWrapper::imguiInterface(Engine* engine) return (2.0f * zNear) / (zFar + zNear - d * (zFar - zNear)); }; - vk_helpers::saveImageR32F(*engine->resourceManager, *engine->immediate, engine->depthImage, + vk_helpers::saveImageR32F(*engine->resourceManager, *engine->immediate, engine->depthStencilImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT, path.string().c_str(), depthNormalize); } @@ -662,17 +668,7 @@ void ImguiWrapper::imguiInterface(Engine* engine) if (ImGui::Button("Save Normals")) { if (file::getOrCreateDirectory(file::imagesSavePath)) { const std::filesystem::path path = file::imagesSavePath / "normalRT.png"; - auto unpackFunc = [](const uint32_t packedColor) { - glm::vec4 pixel = glm::unpackSnorm4x8(packedColor); - pixel.r = pixel.r * 0.5f + 0.5f; - pixel.g = pixel.g * 0.5f + 0.5f; - pixel.b = pixel.b * 0.5f + 0.5f; - pixel.a = 1.0f; - return pixel; - }; - vk_helpers::savePacked32Bit(*engine->resourceManager, *engine->immediate, engine->normalRenderTarget, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, path.string().c_str(), - unpackFunc); + vk_helpers::saveImage(*engine->resourceManager, *engine->immediate, engine->normalRenderTarget, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, vk_helpers::ImageFormat::A2R10G10B10_UNORM, path.string()); } else { fmt::print(" Failed to save normal render target"); @@ -682,14 +678,7 @@ void ImguiWrapper::imguiInterface(Engine* engine) if (ImGui::Button("Save Albedo Render Target")) { if (file::getOrCreateDirectory(file::imagesSavePath)) { const std::filesystem::path path = file::imagesSavePath / "albedoRT.png"; - auto unpackFunc = [](const uint32_t packedColor) { - glm::vec4 pixel = glm::unpackUnorm4x8(packedColor); - pixel.a = 1.0f; - return pixel; - }; - vk_helpers::savePacked32Bit(*engine->resourceManager, *engine->immediate, engine->albedoRenderTarget, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, path.string().c_str(), - unpackFunc); + vk_helpers::saveImage(*engine->resourceManager, *engine->immediate, engine->albedoRenderTarget, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, vk_helpers::ImageFormat::RGBA16F, path.string()); } else { fmt::print(" Failed to save albedo render target"); @@ -699,25 +688,17 @@ void ImguiWrapper::imguiInterface(Engine* engine) if (ImGui::Button("Save PBR Render Target")) { if (file::getOrCreateDirectory(file::imagesSavePath)) { std::filesystem::path path = file::imagesSavePath / "pbrRT.png"; - auto unpackFunc = [](const uint32_t packedColor) { - glm::vec4 pixel = glm::unpackUnorm4x8(packedColor); - pixel.a = 1.0f; - return pixel; - }; - vk_helpers::savePacked32Bit(*engine->resourceManager, *engine->immediate, engine->pbrRenderTarget, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, path.string().c_str(), - unpackFunc); + vk_helpers::saveImage(*engine->resourceManager, *engine->immediate, engine->pbrRenderTarget, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, vk_helpers::ImageFormat::RGBA8_UNORM, path.string()); } else { fmt::print(" Failed to save pbr render target"); } } - if (ImGui::Button("Save Post Process Resolve Target")) { + if (ImGui::Button("Save Final Image")) { if (file::getOrCreateDirectory(file::imagesSavePath)) { - std::filesystem::path path = file::imagesSavePath / "postProcesResolve.png"; - vk_helpers::saveImageRGBA16SFLOAT(*engine->resourceManager, *engine->immediate, engine->postProcessOutputBuffer, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, path.string().c_str()); + std::filesystem::path path = file::imagesSavePath / "finalImage.png"; + vk_helpers::saveImage(*engine->resourceManager, *engine->immediate, engine->finalImageBuffer, VK_IMAGE_LAYOUT_GENERAL, vk_helpers::ImageFormat::RGBA16F, path.string()); } else { fmt::print(" Failed to find/create image save path directory"); @@ -868,7 +849,7 @@ void ImguiWrapper::imguiInterface(Engine* engine) } ImGui::SameLine(); - if (auto container = dynamic_cast(selectedItem)) { + if (auto container = dynamic_cast(engine->selectedItem)) { if (ImGui::Button("Attach to selected item")) { if (!container->getMeshRenderer()) { auto newComponent = components::ComponentFactory::getInstance(). @@ -886,7 +867,7 @@ void ImguiWrapper::imguiInterface(Engine* engine) } else { if (ImGui::Button("Add to Scene")) { - IHierarchical* gob = engine->createGameObject(selectedMap, objectName); + IHierarchical* gob = Engine::createGameObject(selectedMap, objectName); if (auto _container = dynamic_cast(gob)) { auto newComponent = components::ComponentFactory::getInstance().createComponent( @@ -1214,62 +1195,33 @@ void ImguiWrapper::imguiInterface(Engine* engine) ImGui::End(); if (ImGui::Begin("Discardable Debug")) { - if (contactShadowsOutputImguiId == VK_NULL_HANDLE) { - if (engine->contactShadowsPipeline->debugImage.imageView != VK_NULL_HANDLE) { - contactShadowsOutputImguiId = ImGui_ImplVulkan_AddTexture( - engine->resourceManager->getDefaultSamplerNearest(), - engine->contactShadowsPipeline->debugImage.imageView, - VK_IMAGE_LAYOUT_GENERAL); - } - } + ImGui::Checkbox("Draw Debug Render", &engine->bDrawDebugRendering); - if (contactShadowsOutputImguiId == VK_NULL_HANDLE) { - ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Debug texture not available."); - } - else { - // Calculate best fit size - float maxSize = ImGui::GetContentRegionAvail().x; - maxSize = glm::min(maxSize, 1024.0f); - - VkExtent3D imageExtent = engine->contactShadowsPipeline->debugImage.imageExtent; - float width = std::min(maxSize, static_cast(imageExtent.width)); - float aspectRatio = static_cast(imageExtent.width) / static_cast(imageExtent.height); - float height = width / aspectRatio; - - ImGui::Image(reinterpret_cast(contactShadowsOutputImguiId), ImVec2(width, height)); - - if (ImGui::Button("Save SCSS Debug Image")) { - if (file::getOrCreateDirectory(file::imagesSavePath)) { - const std::filesystem::path path = file::imagesSavePath / "scss_debug.png"; - - vk_helpers::saveImageR8G8B8A8UNORM( - *engine->resourceManager, - *engine->immediate, - engine->contactShadowsPipeline->debugImage, - VK_IMAGE_LAYOUT_GENERAL, - path.string().c_str(), - 0 - ); - - ImGui::OpenPopup("SaveConfirmation"); - } + ImGui::Separator(); + if (ImGui::Button("Save Stencil Debug Draw")) { + if (file::getOrCreateDirectory(file::imagesSavePath)) { + const std::filesystem::path path = file::imagesSavePath / "debugStencil.png"; + vk_helpers::saveImage(*engine->resourceManager, *engine->immediate, engine->depthStencilImage, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, vk_helpers::ImageFormat::D32S8, path.string(), true); } - - if (ImGui::BeginPopupModal("SaveConfirmation", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Image saved to %s/gtao_debug.png", file::imagesSavePath.string().c_str()); - if (ImGui::Button("OK", ImVec2(120, 0))) { - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); + else { + fmt::print(" Failed to find/create image save path directory"); } } } ImGui::End(); - if (selectedItem) { - if (IImguiRenderable* imguiRenderable = dynamic_cast(selectedItem)) { + if (engine->selectedItem) { + if (IImguiRenderable* imguiRenderable = dynamic_cast(engine->selectedItem)) { imguiRenderable->selectedRenderImgui(); } + + if (auto gameObject = dynamic_cast(engine->selectedItem)) { + if (components::RigidBodyComponent* rb = gameObject->getRigidbody()) { + if (rb->hasRigidBody()) { + physics::Physics::get()->drawDebug(rb->getPhysicsBodyId()); + } + } + } } ImGui::Render(); @@ -1313,7 +1265,7 @@ void ImguiWrapper::drawSceneGraph(Engine* engine) if (ImGui::BeginTabItem("Scene Graph")) { if (ImGui::Button("Create Game Object")) { static int32_t incrementId{0}; - [[maybe_unused]] IHierarchical* gameObject = engine->createGameObject(selectedMap, fmt::format("New GameObject_{}", incrementId++)); + [[maybe_unused]] IHierarchical* gameObject = Engine::createGameObject(selectedMap, fmt::format("New GameObject_{}", incrementId++)); } ImGui::Separator(); if (!selectedMap->getChildren().empty()) { @@ -1477,7 +1429,7 @@ void ImguiWrapper::drawSceneGraph(Engine* engine) if (destroy) { selectedMap->destroy(); selectMap(nullptr); - selectedItem = nullptr; + deselectItem(engine); } } @@ -1499,8 +1451,8 @@ void ImguiWrapper::displayGameObject(Engine* engine, IHierarchical* obj, const i ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 0, 0, 1)); if (ImGui::Button("X")) { - if (selectedItem == obj) { - selectedItem = nullptr; + if (engine->selectedItem == obj) { + deselectItem(engine); } obj->destroy(); } @@ -1519,7 +1471,7 @@ void ImguiWrapper::displayGameObject(Engine* engine, IHierarchical* obj, const i ? fmt::format("{:.{}s}...", name, std::max(0, maxNameLength - 3)) : fmt::format("{:<{}}", name, maxNameLength); - if (obj == selectedItem) { + if (obj == engine->selectedItem) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.6f, 0.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.7f, 0.0f, 1.0f)); @@ -1527,12 +1479,17 @@ void ImguiWrapper::displayGameObject(Engine* engine, IHierarchical* obj, const i const bool isOpen = ImGui::TreeNodeEx("##TreeNode", flags, "%s", formattedName.c_str()); - if (obj == selectedItem) { + if (obj == engine->selectedItem) { ImGui::PopStyleColor(3); } if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) { - selectedItem = (obj == selectedItem) ? nullptr : obj; + if (obj == engine->selectedItem) { + deselectItem(engine); + } + else { + selectItem(engine, obj); + } } ImGui::NextColumn(); @@ -1669,4 +1626,24 @@ int ImguiWrapper::getIndexInVector(const IHierarchical* obj, const std::vectorselectedItem != nullptr) { + deselectItem(engine); + } + engine->selectedItem = hierarchical; +} + +void ImguiWrapper::deselectItem(Engine* engine) +{ + if (const auto gameObject = dynamic_cast(engine->selectedItem)) { + if (const components::RigidBodyComponent* rb = gameObject->getRigidbody()) { + if (rb->hasRigidBody()) { + physics::Physics::get()->stopDrawDebug(rb->getPhysicsBodyId()); + } + } + } + engine->selectedItem = nullptr; +} } diff --git a/src/renderer/imgui_wrapper.h b/src/renderer/imgui_wrapper.h index a3aae996..8a917d1b 100644 --- a/src/renderer/imgui_wrapper.h +++ b/src/renderer/imgui_wrapper.h @@ -60,12 +60,17 @@ class ImguiWrapper */ static int getIndexInVector(const IHierarchical* obj, const std::vector& vector); +private: + static void selectItem(Engine* engine, IHierarchical* hierarchical); + + static void deselectItem(Engine* engine); + private: const VulkanContext& context; VkDescriptorPool imguiPool{VK_NULL_HANDLE}; - IHierarchical* selectedItem{nullptr}; + Map* selectedMap{nullptr}; uint32_t selectedRenderObjectId = 0; diff --git a/src/renderer/lighting/directional_light.h b/src/renderer/lighting/directional_light.h index f82ad4fb..80957c65 100644 --- a/src/renderer/lighting/directional_light.h +++ b/src/renderer/lighting/directional_light.h @@ -36,6 +36,7 @@ class DirectionalLight DirectionalLightData getData() const { return {direction, intensity, color}; } + // todo: remove friend void ImguiWrapper::imguiInterface(Engine* engine); private: diff --git a/src/renderer/pipelines/basic/basic_compute/basic_compute_pipeline.cpp b/src/renderer/pipelines/basic/basic_compute/basic_compute_pipeline.cpp index 48d00cb7..94728781 100644 --- a/src/renderer/pipelines/basic/basic_compute/basic_compute_pipeline.cpp +++ b/src/renderer/pipelines/basic/basic_compute/basic_compute_pipeline.cpp @@ -34,10 +34,10 @@ BasicComputePipeline::BasicComputePipeline(ResourceManager& resourceManager) : r BasicComputePipeline::~BasicComputePipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyDescriptorSetLayout(descriptorSetLayout); - resourceManager.destroyDescriptorBuffer(samplerDescriptorBuffer); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(descriptorSetLayout); + resourceManager.destroy(samplerDescriptorBuffer); } void BasicComputePipeline::setupDescriptors(const ComputeDescriptorInfo& descriptorInfo) @@ -70,7 +70,7 @@ void BasicComputePipeline::draw(VkCommandBuffer cmd, const ComputeDrawInfo drawI void BasicComputePipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule gradientShader = resourceManager.createShaderModule("shaders/basic/compute.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -89,6 +89,6 @@ void BasicComputePipeline::createPipeline() pipeline = resourceManager.createComputePipeline(computePipelineCreateInfo); - resourceManager.destroyShaderModule(gradientShader); + resourceManager.destroy(gradientShader); } } diff --git a/src/renderer/pipelines/basic/basic_render/basic_render_pipeline.cpp b/src/renderer/pipelines/basic/basic_render/basic_render_pipeline.cpp index 44a7cd96..b064963e 100644 --- a/src/renderer/pipelines/basic/basic_render/basic_render_pipeline.cpp +++ b/src/renderer/pipelines/basic/basic_render/basic_render_pipeline.cpp @@ -40,10 +40,10 @@ will_engine::basic_render_pipeline::BasicRenderPipeline::BasicRenderPipeline(Res will_engine::basic_render_pipeline::BasicRenderPipeline::~BasicRenderPipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyDescriptorSetLayout(samplerDescriptorLayout); - resourceManager.destroyDescriptorBuffer(samplerDescriptorBuffer); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(samplerDescriptorLayout); + resourceManager.destroy(samplerDescriptorBuffer); } void will_engine::basic_render_pipeline::BasicRenderPipeline::setupDescriptors(const RenderDescriptorInfo& descriptorInfo) @@ -112,7 +112,7 @@ void will_engine::basic_render_pipeline::BasicRenderPipeline::draw(VkCommandBuff void will_engine::basic_render_pipeline::BasicRenderPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/basic/vertex.vert"); VkShaderModule fragShader = resourceManager.createShaderModule("shaders/basic/fragment.frag"); @@ -123,11 +123,11 @@ void will_engine::basic_render_pipeline::BasicRenderPipeline::createPipeline() renderPipelineBuilder.disableMultisampling(); renderPipelineBuilder.disableBlending(); renderPipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); - renderPipelineBuilder.setupRenderer({DRAW_FORMAT}, DEPTH_FORMAT); + renderPipelineBuilder.setupRenderer({DRAW_FORMAT}, DEPTH_STENCIL_FORMAT); renderPipelineBuilder.setupPipelineLayout(pipelineLayout); pipeline = resourceManager.createRenderPipeline(renderPipelineBuilder); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); } diff --git a/src/renderer/pipelines/debug/debug_composite_pipeline.cpp b/src/renderer/pipelines/debug/debug_composite_pipeline.cpp new file mode 100644 index 00000000..d7c98281 --- /dev/null +++ b/src/renderer/pipelines/debug/debug_composite_pipeline.cpp @@ -0,0 +1,108 @@ +// +// Created by William on 2025-05-02. +// + +#include "debug_composite_pipeline.h" + +#include "volk/volk.h" + +namespace will_engine::debug_pipeline +{ +DebugCompositePipeline::DebugCompositePipeline(ResourceManager& resourceManager) : resourceManager(resourceManager) +{ + DescriptorLayoutBuilder layoutBuilder; + layoutBuilder.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); // Debug output (flipped image!) + layoutBuilder.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); // Final Image + + descriptorSetLayout = resourceManager.createDescriptorSetLayout(layoutBuilder, VK_SHADER_STAGE_COMPUTE_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); + + std::array setLayouts; + setLayouts[0] = resourceManager.getSceneDataLayout(); + setLayouts[1] = descriptorSetLayout; + + VkPipelineLayoutCreateInfo layoutInfo{}; + layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layoutInfo.pNext = nullptr; + layoutInfo.pSetLayouts = setLayouts.data(); + layoutInfo.setLayoutCount = 2; + layoutInfo.pPushConstantRanges = nullptr; + layoutInfo.pushConstantRangeCount = 0; + + pipelineLayout = resourceManager.createPipelineLayout(layoutInfo); + + createPipeline(); + + descriptorBuffer = resourceManager.createDescriptorBufferSampler(descriptorSetLayout, 1); +} + +DebugCompositePipeline::~DebugCompositePipeline() +{ + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(descriptorSetLayout); + resourceManager.destroy(descriptorBuffer); +} + +void DebugCompositePipeline::setupDescriptorBuffer(VkImageView debugTarget, VkImageView finalImageView) +{ + std::vector descriptors; + descriptors.reserve(2); + + VkDescriptorImageInfo inputImage{}; + inputImage.sampler = resourceManager.getDefaultSamplerNearest(); + inputImage.imageView = debugTarget; + inputImage.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + VkDescriptorImageInfo outputImage{}; + outputImage.imageView = finalImageView; + outputImage.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + descriptors.push_back({VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, inputImage, false}); + descriptors.push_back({VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outputImage, false}); + + resourceManager.setupDescriptorBufferSampler(descriptorBuffer, descriptors, 0); +} + +void DebugCompositePipeline::draw(VkCommandBuffer cmd, DebugCompositePipelineDrawInfo drawInfo) const +{ + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); + + const std::array bindingInfos{ + drawInfo.sceneDataBinding, + descriptorBuffer.getDescriptorBufferBindingInfo() + }; + vkCmdBindDescriptorBuffersEXT(cmd, 2, bindingInfos.data()); + + constexpr std::array indices{0, 1}; + const std::array offsets{drawInfo.sceneDataOffset, 0}; + vkCmdSetDescriptorBufferOffsetsEXT(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 2, indices.data(), offsets.data()); + + const auto x = static_cast(std::ceil(RENDER_EXTENT_WIDTH / 16.0f)); + const auto y = static_cast(std::ceil(RENDER_EXTENT_HEIGHT / 16.0f)); + vkCmdDispatch(cmd, x, y, 1); +} + +void DebugCompositePipeline::createPipeline() +{ + resourceManager.destroy(pipeline); + VkShaderModule computeShader = resourceManager.createShaderModule("shaders/debug/debug_composite.comp"); + + VkPipelineShaderStageCreateInfo stageInfo{}; + stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo.pNext = nullptr; + stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageInfo.module = computeShader; + stageInfo.pName = "main"; + + VkComputePipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipelineInfo.pNext = nullptr; + pipelineInfo.layout = pipelineLayout; + pipelineInfo.stage = stageInfo; + pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; + + pipeline = resourceManager.createComputePipeline(pipelineInfo); + resourceManager.destroy(computeShader); +} +} diff --git a/src/renderer/pipelines/debug/debug_composite_pipeline.h b/src/renderer/pipelines/debug/debug_composite_pipeline.h new file mode 100644 index 00000000..5b430ab7 --- /dev/null +++ b/src/renderer/pipelines/debug/debug_composite_pipeline.h @@ -0,0 +1,46 @@ +// +// Created by William on 2025-05-02. +// + +#ifndef DEBUG_PIPELINE_H +#define DEBUG_PIPELINE_H + + +#include "src/renderer/resource_manager.h" + + +namespace will_engine::debug_pipeline +{ +struct DebugCompositePipelineDrawInfo +{ + VkDescriptorBufferBindingInfoEXT sceneDataBinding{}; + VkDeviceSize sceneDataOffset{0}; +}; + +class DebugCompositePipeline { +public: + explicit DebugCompositePipeline(ResourceManager& resourceManager); + + ~DebugCompositePipeline(); + + void setupDescriptorBuffer(VkImageView debugTarget, VkImageView finalImageView); + + void draw(VkCommandBuffer cmd, DebugCompositePipelineDrawInfo drawInfo) const; + + void reloadShaders() { createPipeline(); } + +private: + void createPipeline(); + +private: + ResourceManager& resourceManager; + + VkPipelineLayout pipelineLayout{VK_NULL_HANDLE}; + VkPipeline pipeline{VK_NULL_HANDLE}; + VkDescriptorSetLayout descriptorSetLayout{VK_NULL_HANDLE}; + DescriptorBufferSampler descriptorBuffer; +}; + +} + +#endif //DEBUG_PIPELINE_H diff --git a/src/renderer/pipelines/debug/debug_highlighter.cpp b/src/renderer/pipelines/debug/debug_highlighter.cpp new file mode 100644 index 00000000..701fffd1 --- /dev/null +++ b/src/renderer/pipelines/debug/debug_highlighter.cpp @@ -0,0 +1,248 @@ +// +// Created by William on 2025-05-04. +// + +#include "debug_highlighter.h" + +#include + +#include "src/core/game_object/renderable.h" +#include "src/renderer/assets/render_object/render_object_types.h" + + +namespace will_engine::debug_highlight_pipeline +{ +DebugHighlighter::DebugHighlighter(ResourceManager& resourceManager) : resourceManager(resourceManager) +{ + std::array descriptorLayout; + descriptorLayout[0] = resourceManager.getSceneDataLayout(); + + VkPushConstantRange pushConstants{}; + pushConstants.offset = 0; + pushConstants.size = sizeof(DebugHighlightDrawPushConstant); + pushConstants.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkPipelineLayoutCreateInfo layoutInfo = vk_helpers::pipelineLayoutCreateInfo(); + layoutInfo.pNext = nullptr; + layoutInfo.pSetLayouts = descriptorLayout.data(); + layoutInfo.setLayoutCount = 1; + layoutInfo.pPushConstantRanges = &pushConstants; + layoutInfo.pushConstantRangeCount = 1; + + pipelineLayout = resourceManager.createPipelineLayout(layoutInfo); + + DescriptorLayoutBuilder layoutBuilder; + layoutBuilder.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); // Stencil Image + layoutBuilder.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); // Debug Target + + processingSetLayout = resourceManager.createDescriptorSetLayout(layoutBuilder, VK_SHADER_STAGE_COMPUTE_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); + + descriptorLayout[1] = processingSetLayout; + + layoutInfo.setLayoutCount = 2; + layoutInfo.pPushConstantRanges = nullptr; + layoutInfo.pushConstantRangeCount = 0; + + processingPipelineLayout = resourceManager.createPipelineLayout(layoutInfo); + + createPipeline(); + + descriptorBuffer = resourceManager.createDescriptorBufferSampler(processingSetLayout, 1); +} + +DebugHighlighter::~DebugHighlighter() +{ + resourceManager.destroy(processingSetLayout); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(processingPipelineLayout); + resourceManager.destroy(pipeline); + resourceManager.destroy(processingPipeline); + resourceManager.destroy(descriptorBuffer); +} + +void DebugHighlighter::setupDescriptorBuffer(VkImageView stencilImageView, VkImageView debugTarget) +{ + std::vector descriptors; + descriptors.reserve(2); + + VkDescriptorImageInfo inputImage{}; + inputImage.imageView = stencilImageView; + inputImage.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + VkDescriptorImageInfo outputImage{}; + outputImage.imageView = debugTarget; + outputImage.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + descriptors.push_back({VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, inputImage, false}); + descriptors.push_back({VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outputImage, false}); + + resourceManager.setupDescriptorBufferSampler(descriptorBuffer, descriptors, 0); +} + +bool DebugHighlighter::drawHighlightStencil(VkCommandBuffer cmd, const DebugHighlighterDrawInfo& drawInfo) const +{ + if (IRenderReference* renderRef = drawInfo.highlightTarget->getRenderReference()) { + const std::optional > meshData = renderRef->getMeshData(drawInfo.highlightTarget->getMeshIndex()); + if (meshData.has_value()) { + const VkRenderingAttachmentInfo depthAttachment = vk_helpers::attachmentInfo(drawInfo.depthStencilTarget.imageView, nullptr, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + VkClearValue stencilClear{}; + stencilClear.depthStencil = {0.0f, 0}; + const VkRenderingAttachmentInfo stencilAttachment = vk_helpers::attachmentInfo(drawInfo.depthStencilTarget.imageView, &stencilClear, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + VkRenderingInfo renderInfo{}; + renderInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + renderInfo.pNext = nullptr; + + renderInfo.renderArea = VkRect2D{VkOffset2D{0, 0}, RENDER_EXTENTS}; + renderInfo.layerCount = 1; + renderInfo.colorAttachmentCount = 0; + renderInfo.pColorAttachments = nullptr; + renderInfo.pDepthAttachment = &depthAttachment; + renderInfo.pStencilAttachment = &stencilAttachment; + + vkCmdBeginRendering(cmd, &renderInfo); + + vkCmdSetLineWidth(cmd, 2.0f); + + // Viewport + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = RENDER_EXTENTS.width; + viewport.height = RENDER_EXTENTS.height; + viewport.minDepth = 0.f; + viewport.maxDepth = 1.f; + vkCmdSetViewport(cmd, 0, 1, &viewport); + // Scissor + VkRect2D scissor = {}; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = RENDER_EXTENTS.width; + scissor.extent.height = RENDER_EXTENTS.height; + vkCmdSetScissor(cmd, 0, 1, &scissor); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + + const std::array bindingInfos{ + drawInfo.sceneDataBinding, + }; + vkCmdBindDescriptorBuffersEXT(cmd, 1, bindingInfos.data()); + + constexpr std::array indices{0u}; + const std::array offsets{drawInfo.sceneDataOffset}; + vkCmdSetDescriptorBufferOffsetsEXT(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, indices.data(), offsets.data()); + + + for (const Primitive& primitive : meshData.value().get().primitives) { + const uint32_t indexCount = primitive.indexCount; + const uint32_t firstIndex = primitive.firstIndex; + const int32_t vertexOffset = primitive.vertexOffset; + constexpr uint32_t firstInstance = 0; + constexpr uint32_t instanceCount = 1; + + DebugHighlightDrawPushConstant push{}; + push.modelMatrix = drawInfo.highlightTarget->getModelMatrix(); + vkCmdPushConstants(cmd, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(DebugHighlightDrawPushConstant), &push); + + vkCmdBindVertexBuffers(cmd, 0, 1, &renderRef->getPositionVertexBuffer().buffer, &ZERO_DEVICE_SIZE); + vkCmdBindIndexBuffer(cmd, renderRef->getIndexBuffer().buffer, 0, VK_INDEX_TYPE_UINT32); + + // Draw this mesh w/ vkCmdDrawIndexed w/ model matrix passed through push + vkCmdDrawIndexed(cmd, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + } + + vkCmdEndRendering(cmd); + return true; + } + } + return false; +} + +void DebugHighlighter::drawHighlightProcessing(VkCommandBuffer cmd, const DebugHighlighterDrawInfo& drawInfo) const +{ + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, processingPipeline); + + const std::array bindingInfos{ + drawInfo.sceneDataBinding, + descriptorBuffer.getDescriptorBufferBindingInfo() + }; + vkCmdBindDescriptorBuffersEXT(cmd, 2, bindingInfos.data()); + + constexpr std::array indices{0, 1}; + const std::array offsets{drawInfo.sceneDataOffset, 0}; + vkCmdSetDescriptorBufferOffsetsEXT(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, processingPipelineLayout, 0, 2, indices.data(), offsets.data()); + + const auto x = static_cast(std::ceil(RENDER_EXTENT_WIDTH / 16.0f)); + const auto y = static_cast(std::ceil(RENDER_EXTENT_HEIGHT / 16.0f)); + vkCmdDispatch(cmd, x, y, 1); +} + + +void DebugHighlighter::createPipeline() +{ + VkShaderModule vertShader = resourceManager.createShaderModule("shaders/debug/debug_highlighter.vert"); + VkShaderModule fragShader = resourceManager.createShaderModule("shaders/debug/debug_highlighter.frag"); + + PipelineBuilder renderPipelineBuilder; + VkVertexInputBindingDescription vertexBinding{}; + vertexBinding.binding = 0; + vertexBinding.stride = sizeof(VertexPosition); + vertexBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertexAttributes; + vertexAttributes[0].binding = 0; + vertexAttributes[0].location = 0; + vertexAttributes[0].format = VK_FORMAT_R32G32B32_SFLOAT; + vertexAttributes[0].offset = offsetof(VertexPosition, position); + + renderPipelineBuilder.setupVertexInput(&vertexBinding, 1, vertexAttributes.data(), 1); + + renderPipelineBuilder.setShaders(vertShader, fragShader); + renderPipelineBuilder.setupInputAssembly(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + renderPipelineBuilder.setupRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); + renderPipelineBuilder.disableMultisampling(); + renderPipelineBuilder.disableBlending(); + constexpr VkStencilOpState stencilOp = { + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_REPLACE, + VK_COMPARE_OP_ALWAYS, + 0xff, + 0xff, + 1 + }; + renderPipelineBuilder.setupDepthStencil(VK_TRUE, VK_TRUE, VK_COMPARE_OP_GREATER_OR_EQUAL, VK_FALSE, VK_TRUE, stencilOp, stencilOp, 0.0f, 1.0f); + renderPipelineBuilder.setupRenderer({}, DEPTH_STENCIL_FORMAT, DEPTH_STENCIL_FORMAT); + renderPipelineBuilder.setupPipelineLayout(pipelineLayout); + const std::vector additionalDynamicStates{VK_DYNAMIC_STATE_LINE_WIDTH}; + pipeline = resourceManager.createRenderPipeline(renderPipelineBuilder, additionalDynamicStates); + + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); + + + resourceManager.destroy(processingPipeline); + VkShaderModule computeShader = resourceManager.createShaderModule("shaders/debug/debug_highlighter_processing.comp"); + + VkPipelineShaderStageCreateInfo stageInfo{}; + stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo.pNext = nullptr; + stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageInfo.module = computeShader; + stageInfo.pName = "main"; + + VkComputePipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipelineInfo.pNext = nullptr; + pipelineInfo.layout = processingPipelineLayout; + pipelineInfo.stage = stageInfo; + pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; + + processingPipeline = resourceManager.createComputePipeline(pipelineInfo); + resourceManager.destroy(computeShader); +} +} diff --git a/src/renderer/pipelines/debug/debug_highlighter.h b/src/renderer/pipelines/debug/debug_highlighter.h new file mode 100644 index 00000000..bc8ef7f5 --- /dev/null +++ b/src/renderer/pipelines/debug/debug_highlighter.h @@ -0,0 +1,72 @@ +// +// Created by William on 2025-05-04. +// + +#ifndef DEBUG_HIGHLIGHT_PIPELINE_H +#define DEBUG_HIGHLIGHT_PIPELINE_H + +#include + +#include "src/core/game_object/renderable.h" +#include "src/renderer/imgui_wrapper.h" +#include "src/renderer/resource_manager.h" + +namespace will_engine +{ +class IRenderable; +} + +namespace will_engine::debug_highlight_pipeline +{ +struct DebugHighlightDrawPushConstant +{ + glm::mat4 modelMatrix{1.0f}; + glm::vec4 color{1.0f, 0.647f, 0.0f, 1.0f}; +}; + +struct DebugHighlighterDrawInfo +{ + IRenderable* highlightTarget{nullptr}; + AllocatedImage depthStencilTarget{VK_NULL_HANDLE}; + VkDescriptorBufferBindingInfoEXT sceneDataBinding{}; + VkDeviceSize sceneDataOffset{0}; +}; + +class DebugHighlighter { +public: + explicit DebugHighlighter(ResourceManager& resourceManager); + + ~DebugHighlighter(); + + void setupDescriptorBuffer(VkImageView stencilImageView, VkImageView debugTarget); + + bool drawHighlightStencil(VkCommandBuffer cmd, const DebugHighlighterDrawInfo& drawInfo) const; + + void drawHighlightProcessing(VkCommandBuffer cmd, const DebugHighlighterDrawInfo& drawInfo) const; + + void reloadShaders() { createPipeline(); } + +private: + void createPipeline(); + +private: + ResourceManager& resourceManager; + + VkPipelineLayout pipelineLayout{VK_NULL_HANDLE}; + VkPipeline pipeline{VK_NULL_HANDLE}; + + VkDescriptorSetLayout processingSetLayout{VK_NULL_HANDLE}; + VkPipelineLayout processingPipelineLayout{VK_NULL_HANDLE}; + VkPipeline processingPipeline{VK_NULL_HANDLE}; + DescriptorBufferSampler descriptorBuffer{}; + + // todo: remove + friend void ImguiWrapper::imguiInterface(Engine* engine); +}; +} + + + + + +#endif //DEBUG_HIGHLIGHT_PIPELINE_H diff --git a/src/renderer/pipelines/debug/debug_renderer.cpp b/src/renderer/pipelines/debug/debug_renderer.cpp new file mode 100644 index 00000000..5a1a6d3f --- /dev/null +++ b/src/renderer/pipelines/debug/debug_renderer.cpp @@ -0,0 +1,605 @@ +// +// Created by William on 2025-04-27. +// + + +#include "debug_renderer.h" + +#include +#include +#include + +#include "src/renderer/resource_manager.h" + + +namespace will_engine::debug_renderer +{ +DebugRenderer* DebugRenderer::debugRenderer = nullptr; + +DebugRenderer::DebugRenderer(ResourceManager& resourceManager) : resourceManager(resourceManager) +{ + DescriptorLayoutBuilder layoutBuilder; + layoutBuilder.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + uniformLayout = resourceManager.createDescriptorSetLayout(layoutBuilder, VK_SHADER_STAGE_VERTEX_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); + + setupBoxRendering(BOX_INSTANCE_INDEX); + setupSphereRendering(SPHERE_INSTANCE_INDEX); + setupLineRendering(); + + // Vertex Buffer + const uint64_t instancedVertexBufferSize = instancedVertices.size() * sizeof(DebugRendererVertex); + const AllocatedBuffer instancedVertexStaging = resourceManager.createStagingBuffer(instancedVertexBufferSize); + memcpy(instancedVertexStaging.info.pMappedData, instancedVertices.data(), instancedVertexBufferSize); + instancedVertexBuffer = resourceManager.createDeviceBuffer(instancedVertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + + // Index Buffer + const uint64_t instancedIndexBufferSize = instancedIndices.size() * sizeof(uint32_t); + const AllocatedBuffer instancedIndexStaging = resourceManager.createStagingBuffer(instancedIndexBufferSize); + memcpy(instancedIndexStaging.info.pMappedData, instancedIndices.data(), instancedIndexBufferSize); + instancedIndexBuffer = resourceManager.createDeviceBuffer(instancedIndexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + + std::array bufferCopies = { + BufferCopyInfo(instancedVertexStaging, 0, instancedVertexBuffer, 0, instancedVertexBufferSize), + {instancedIndexStaging, 0, instancedIndexBuffer, 0, instancedIndexBufferSize}, + }; + + resourceManager.copyBufferImmediate(bufferCopies); + for (BufferCopyInfo bufferCopy : bufferCopies) { + resourceManager.destroyImmediate(bufferCopy.src); + } + + + std::array descriptorLayout; + descriptorLayout[0] = resourceManager.getSceneDataLayout(); + descriptorLayout[1] = uniformLayout; + + VkPipelineLayoutCreateInfo layoutInfo = vk_helpers::pipelineLayoutCreateInfo(); + layoutInfo.pSetLayouts = descriptorLayout.data(); + layoutInfo.pNext = nullptr; + layoutInfo.setLayoutCount = 2; + layoutInfo.pPushConstantRanges = nullptr; + layoutInfo.pushConstantRangeCount = 0; + + instancedPipelineLayout = resourceManager.createPipelineLayout(layoutInfo); + + layoutInfo.setLayoutCount = 1; + normalPipelineLayout = resourceManager.createPipelineLayout(layoutInfo); + + createPipeline(); +} + +DebugRenderer::~DebugRenderer() +{ + resourceManager.destroy(uniformLayout); + + resourceManager.destroy(instancedVertexBuffer); + resourceManager.destroy(instancedIndexBuffer); + + for (DebugRenderGroup& group : debugRenderInstanceGroups) { + for (AllocatedBuffer& buffer : group.instanceBuffers) { + resourceManager.destroy(buffer); + } + resourceManager.destroy(group.instanceDescriptorBuffer); + } + + for (AllocatedBuffer& buffer : lineVertexBuffers) { + resourceManager.destroy(buffer); + } + for (AllocatedBuffer& buffer : triangleVertexBuffers) { + resourceManager.destroy(buffer); + } + + resourceManager.destroy(instancedPipelineLayout); + resourceManager.destroy(normalPipelineLayout); + resourceManager.destroy(instancedLinePipeline); + resourceManager.destroy(linePipeline); + resourceManager.destroy(trianglePipeline); +} + +void DebugRenderer::drawLine(const glm::vec3& start, const glm::vec3& end, const glm::vec3& color) +{ + DebugRenderer* inst = get(); + if (!inst) { return; } + inst->drawLineImpl(start, end, color); +} + +void DebugRenderer::drawTriangle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3, const glm::vec3& color) +{ + DebugRenderer* inst = get(); + if (!inst) { return; } + inst->drawTriangleImpl(v1, v2, v3, color); +} + +void DebugRenderer::drawSphere(const glm::vec3& center, float radius, const glm::vec3& color, DebugRendererCategory category) +{ + DebugRenderer* inst = get(); + if (!inst) { return; } + inst->drawSphereImpl(center, radius, color, category); +} + +void DebugRenderer::drawBox(const glm::vec3& center, const glm::vec3& dimensions, const glm::vec3& color, DebugRendererCategory category) +{ + DebugRenderer* inst = get(); + if (!inst) { return; } + inst->drawBoxImpl(center, dimensions, color, category); +} + +void DebugRenderer::drawBoxMinMax(const glm::vec3& min, const glm::vec3& max, const glm::vec3& color, DebugRendererCategory category) +{ + DebugRenderer* inst = get(); + if (!inst) { return; } + inst->drawBoxMinMaxImpl(min, max, color, category); +} + +void DebugRenderer::draw(VkCommandBuffer cmd, const DebugRendererDrawInfo& drawInfo) +{ + if (drawInfo.currentFrameOverlap < 0 || drawInfo.currentFrameOverlap >= FRAME_OVERLAP) { return; } + + // Upload + for (DebugRenderGroup& group : debugRenderInstanceGroups) { + if (group.instances.empty()) { continue; } + + AllocatedBuffer& instanceBuffer = group.instanceBuffers[drawInfo.currentFrameOverlap]; + + if (group.instances.size() > group.instanceBufferSizes[drawInfo.currentFrameOverlap]) { + uint64_t newSize = group.instanceBufferSizes[drawInfo.currentFrameOverlap]; + // Can potentially overflow resulting in infinite loop, but it would need to be so insanely large, cant even create a buffer that big + while (group.instances.size() > newSize) { + newSize += DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + } + + resourceManager.destroy(instanceBuffer); + + // Don't need to copy, writing to it in the next section anyway + const uint64_t newBufferSize = newSize * sizeof(DebugRendererInstance); + instanceBuffer = resourceManager.createHostSequentialBuffer(newBufferSize); + + DescriptorUniformData addressesUniformData{ + .uniformBuffer = instanceBuffer, + .allocSize = newBufferSize, + }; + + resourceManager.setupDescriptorBufferUniform(group.instanceDescriptorBuffer, {addressesUniformData}, drawInfo.currentFrameOverlap); + + group.instanceBufferSizes[drawInfo.currentFrameOverlap] = newSize; + } + + memcpy(instanceBuffer.info.pMappedData, group.instances.data(), sizeof(DebugRendererInstance) * group.instances.size()); + } + + // Upload Vertex Data + { + AllocatedBuffer& lineVertexBuffer = lineVertexBuffers[drawInfo.currentFrameOverlap]; + + if (lineVertices.size() > lineVertexBufferSizes[drawInfo.currentFrameOverlap]) { + int64_t newSize = lineVertexBufferSizes[drawInfo.currentFrameOverlap]; + while (lineVertices.size() > newSize) { + newSize += DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + } + + resourceManager.destroy(lineVertexBuffer); + + const uint64_t newBufferSize = newSize * sizeof(DebugRendererVertexFull); + lineVertexBuffer = resourceManager.createHostSequentialBuffer(newBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + lineVertexBufferSizes[drawInfo.currentFrameOverlap] = newSize; + } + + memcpy(lineVertexBuffer.info.pMappedData, lineVertices.data(), sizeof(DebugRendererVertexFull) * lineVertices.size()); + + AllocatedBuffer& triangleVertexBuffer = triangleVertexBuffers[drawInfo.currentFrameOverlap]; + + if (triangleVertices.size() > triangleVertexBufferSizes[drawInfo.currentFrameOverlap]) { + int64_t newSize = triangleVertexBufferSizes[drawInfo.currentFrameOverlap]; + while (triangleVertices.size() > newSize) { + newSize += DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + } + + resourceManager.destroy(triangleVertexBuffer); + + const uint64_t newBufferSize = newSize * sizeof(DebugRendererVertexFull); + triangleVertexBuffer = resourceManager.createHostSequentialBuffer(newBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + triangleVertexBufferSizes[drawInfo.currentFrameOverlap] = newSize; + } + + memcpy(triangleVertexBuffer.info.pMappedData, triangleVertices.data(), sizeof(DebugRendererVertexFull) * triangleVertices.size()); + } + + + const VkRenderingAttachmentInfo imageAttachment = vk_helpers::attachmentInfo(drawInfo.debugTarget, nullptr, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + const VkRenderingAttachmentInfo depthAttachment = vk_helpers::attachmentInfo(drawInfo.depthTarget, nullptr, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); + + VkRenderingInfo renderInfo{}; + renderInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + renderInfo.pNext = nullptr; + + VkRenderingAttachmentInfo renderAttachments[1]; + renderAttachments[0] = imageAttachment; + + renderInfo.renderArea = VkRect2D{VkOffset2D{0, 0}, RENDER_EXTENTS}; + renderInfo.layerCount = 1; + renderInfo.colorAttachmentCount = 1; + renderInfo.pColorAttachments = renderAttachments; + renderInfo.pDepthAttachment = &depthAttachment; + renderInfo.pStencilAttachment = nullptr; + + vkCmdBeginRendering(cmd, &renderInfo); + + vkCmdSetLineWidth(cmd, 1.0f); + + // Viewport + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = RENDER_EXTENTS.width; + viewport.height = RENDER_EXTENTS.height; + viewport.minDepth = 0.f; + viewport.maxDepth = 1.f; + vkCmdSetViewport(cmd, 0, 1, &viewport); + // Scissor + VkRect2D scissor = {}; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = RENDER_EXTENTS.width; + scissor.extent.height = RENDER_EXTENTS.height; + vkCmdSetScissor(cmd, 0, 1, &scissor); + + // Instanced rendering + { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, instancedLinePipeline); + + for (DebugRenderGroup& group : debugRenderInstanceGroups) { + if (group.instances.empty()) { continue;; } + + + const std::array descriptorBufferBindingInfos{ + drawInfo.sceneDataBinding, + group.instanceDescriptorBuffer.getDescriptorBufferBindingInfo() + }; + + vkCmdBindDescriptorBuffersEXT(cmd, 2, descriptorBufferBindingInfos.data()); + + constexpr std::array indices{0, 1}; + const std::array offsets{ + drawInfo.sceneDataOffset, + group.instanceDescriptorBuffer.getDescriptorBufferSize() * drawInfo.currentFrameOverlap, + }; + + vkCmdSetDescriptorBufferOffsetsEXT(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, instancedPipelineLayout, 0, 2, indices.data(), offsets.data()); + + vkCmdBindVertexBuffers(cmd, 0, 1, &instancedVertexBuffer.buffer, &ZERO_DEVICE_SIZE); + vkCmdBindIndexBuffer(cmd, instancedIndexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + + + vkCmdDrawIndexed(cmd, group.drawIndexedData.indexCount, group.instances.size(), group.drawIndexedData.firstIndex + , group.drawIndexedData.vertexOffset, group.drawIndexedData.firstInstance); + } + } + + // Line Rendering + if (!lineVertices.empty()) { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, linePipeline); + + const std::array descriptorBufferBindingInfos{drawInfo.sceneDataBinding}; + constexpr std::array indices{}; + const std::array offsets{drawInfo.sceneDataOffset}; + vkCmdBindDescriptorBuffersEXT(cmd, 1, descriptorBufferBindingInfos.data()); + vkCmdSetDescriptorBufferOffsetsEXT(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, normalPipelineLayout, 0, 1, indices.data(), offsets.data()); + + AllocatedBuffer& currentLineVertexBuffer = lineVertexBuffers[drawInfo.currentFrameOverlap]; + vkCmdBindVertexBuffers(cmd, 0, 1, ¤tLineVertexBuffer.buffer, &ZERO_DEVICE_SIZE); + vkCmdDraw(cmd, lineVertices.size(), 1, 0, 0); + } + + if (!triangleVertices.empty()) { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, trianglePipeline); + + const std::array descriptorBufferBindingInfos{drawInfo.sceneDataBinding}; + constexpr std::array indices{}; + const std::array offsets{drawInfo.sceneDataOffset}; + vkCmdBindDescriptorBuffersEXT(cmd, 1, descriptorBufferBindingInfos.data()); + vkCmdSetDescriptorBufferOffsetsEXT(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, normalPipelineLayout, 0, 1, indices.data(), offsets.data()); + + AllocatedBuffer& currentTriangleVertexBuffer = triangleVertexBuffers[drawInfo.currentFrameOverlap]; + vkCmdBindVertexBuffers(cmd, 0, 1, ¤tTriangleVertexBuffer.buffer, &ZERO_DEVICE_SIZE); + vkCmdDraw(cmd, triangleVertices.size(), 1, 0, 0); + } + + vkCmdEndRendering(cmd); + + clear(); +} + +void DebugRenderer::clear() +{ + for (DebugRenderGroup& group : debugRenderInstanceGroups) { + group.instances.clear(); + } + lineVertices.clear(); + triangleVertices.clear(); +} + +void DebugRenderer::createPipeline() +{ + resourceManager.destroy(instancedLinePipeline); + resourceManager.destroy(trianglePipeline); + resourceManager.destroy(linePipeline); + + // Instanced Pipeline + { + VkShaderModule vertShader = resourceManager.createShaderModule("shaders/debug/debug_renderer_instanced.vert"); + VkShaderModule fragShader = resourceManager.createShaderModule("shaders/debug/debug_renderer_instanced.frag"); + + PipelineBuilder renderPipelineBuilder; + VkVertexInputBindingDescription vertexBinding{}; + vertexBinding.binding = 0; + vertexBinding.stride = sizeof(DebugRendererVertex); + vertexBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertexAttributes; + vertexAttributes[0].binding = 0; + vertexAttributes[0].location = 0; + vertexAttributes[0].format = VK_FORMAT_R32G32B32_SFLOAT; + vertexAttributes[0].offset = offsetof(DebugRendererVertex, position); + + renderPipelineBuilder.setupVertexInput(&vertexBinding, 1, vertexAttributes.data(), 1); + + renderPipelineBuilder.setShaders(vertShader, fragShader); + renderPipelineBuilder.setupInputAssembly(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); // line so that we don't see diagonals on quads + renderPipelineBuilder.setupRasterization(VK_POLYGON_MODE_LINE, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); + renderPipelineBuilder.disableMultisampling(); + renderPipelineBuilder.disableBlending(); + renderPipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); + renderPipelineBuilder.setupRenderer({DEBUG_FORMAT}, DEPTH_STENCIL_FORMAT); + renderPipelineBuilder.setupPipelineLayout(instancedPipelineLayout); + const std::vector additionalDynamicStates{VK_DYNAMIC_STATE_LINE_WIDTH}; + instancedLinePipeline = resourceManager.createRenderPipeline(renderPipelineBuilder, additionalDynamicStates); + + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); + } + + // Line Vertex Pipeline + { + VkShaderModule vertShader = resourceManager.createShaderModule("shaders/debug/debug_renderer.vert"); + VkShaderModule fragShader = resourceManager.createShaderModule("shaders/debug/debug_renderer.frag"); + + PipelineBuilder renderPipelineBuilder; + VkVertexInputBindingDescription vertexBinding{}; + vertexBinding.binding = 0; + vertexBinding.stride = sizeof(DebugRendererVertexFull); + vertexBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertexAttributes; + vertexAttributes[0].binding = 0; + vertexAttributes[0].location = 0; + vertexAttributes[0].format = VK_FORMAT_R32G32B32_SFLOAT; + vertexAttributes[0].offset = offsetof(DebugRendererVertexFull, position); + + vertexAttributes[1].binding = 0; + vertexAttributes[1].location = 1; + vertexAttributes[1].format = VK_FORMAT_R32G32B32_SFLOAT; + vertexAttributes[1].offset = offsetof(DebugRendererVertexFull, color); + + renderPipelineBuilder.setupVertexInput(&vertexBinding, 1, vertexAttributes.data(), 2); + + renderPipelineBuilder.setShaders(vertShader, fragShader); + renderPipelineBuilder.setupInputAssembly(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); + renderPipelineBuilder.setupRasterization(VK_POLYGON_MODE_LINE, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); + renderPipelineBuilder.disableMultisampling(); + renderPipelineBuilder.disableBlending(); + renderPipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); + renderPipelineBuilder.setupRenderer({DEBUG_FORMAT}, DEPTH_STENCIL_FORMAT); + renderPipelineBuilder.setupPipelineLayout(normalPipelineLayout); + const std::vector additionalDynamicStates{VK_DYNAMIC_STATE_LINE_WIDTH}; + linePipeline = resourceManager.createRenderPipeline(renderPipelineBuilder, additionalDynamicStates); + + //renderPipelineBuilder.setupRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); + renderPipelineBuilder.setupInputAssembly(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + trianglePipeline = resourceManager.createRenderPipeline(renderPipelineBuilder, additionalDynamicStates); + + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); + } +} + +void DebugRenderer::drawLineImpl(const glm::vec3& start, const glm::vec3& end, const glm::vec3& color) +{ + lineVertices.push_back({start, color}); + lineVertices.push_back({end, color}); +} + +void DebugRenderer::drawTriangleImpl(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3, const glm::vec3& color) +{ + triangleVertices.push_back({v1, color}); + triangleVertices.push_back({v2, color}); + triangleVertices.push_back({v3, color}); +} + +void DebugRenderer::drawSphereImpl(const glm::vec3& center, const float radius, const glm::vec3& color, DebugRendererCategory category) +{ + if (!hasFlag(activeCategories, category)) { return; } + + const glm::mat4 transform = glm::translate(glm::mat4(1.0f), center) * glm::scale(glm::mat4(1.0f), glm::vec3(radius)); + + DebugRendererInstance instance{}; + instance.transform = transform; + instance.color = color; + + debugRenderInstanceGroups[SPHERE_INSTANCE_INDEX].instances.push_back(instance); +} + +void DebugRenderer::drawBoxImpl(const glm::vec3& center, const glm::vec3& dimensions, const glm::vec3& color, const DebugRendererCategory category) +{ + if (!hasFlag(activeCategories, category)) { return; } + + const glm::mat4 transform = glm::translate(glm::mat4(1.0f), center) * glm::scale(glm::mat4(1.0f), dimensions); + + DebugRendererInstance instance{}; + instance.transform = transform; + instance.color = color; + + debugRenderInstanceGroups[BOX_INSTANCE_INDEX].instances.push_back(instance); +} + +void DebugRenderer::drawBoxMinMaxImpl(const glm::vec3& min, const glm::vec3& max, const glm::vec3& color, const DebugRendererCategory category) +{ + if (!hasFlag(activeCategories, category)) { return; } + + const glm::vec3 size = max - min; + const glm::vec3 center = min + size * 0.5f; + + drawBoxImpl(center, size, color, category); +} + +void DebugRenderer::setupBoxRendering(const int32_t index) +{ + // Box Instance Data Buffer + constexpr uint64_t boxInstanceBufferSize = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT * sizeof(DebugRendererInstance); + + debugRenderInstanceGroups[index].instanceDescriptorBuffer = resourceManager.createDescriptorBufferUniform(uniformLayout, FRAME_OVERLAP); + for (int32_t i = 0; i < FRAME_OVERLAP; ++i) { + debugRenderInstanceGroups[index].instanceBufferSizes[i] = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + debugRenderInstanceGroups[index].instanceBuffers[i] = resourceManager.createHostSequentialBuffer(boxInstanceBufferSize); + DescriptorUniformData addressesUniformData{ + .uniformBuffer = debugRenderInstanceGroups[index].instanceBuffers[i], + .allocSize = boxInstanceBufferSize, + }; + + resourceManager.setupDescriptorBufferUniform(debugRenderInstanceGroups[index].instanceDescriptorBuffer, {addressesUniformData}, i); + } + + + debugRenderInstanceGroups[index].instances.reserve(DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT); + // 8 vertices, 12 edges (24 points) + constexpr int32_t boxVertexCount = 8; + constexpr int32_t boxIndicesCount = 24; + instancedVertices.reserve(instancedVertices.size() + boxVertexCount); + instancedIndices.reserve(instancedIndices.size() + boxIndicesCount); + + std::vector boxVertices = { + {{-0.5, -0.5, -0.5}}, // 0: near bottom left + {{0.5, -0.5, -0.5}}, // 1: near bottom right + {{0.5, 0.5, -0.5}}, // 2: near top right + {{-0.5, 0.5, -0.5}}, // 3: near top left + {{-0.5, -0.5, 0.5}}, // 4: far bottom left + {{0.5, -0.5, 0.5}}, // 5: far bottom right + {{0.5, 0.5, 0.5}}, // 6: far top right + {{-0.5, 0.5, 0.5}} // 7: far top left + }; + + std::vector boxIndices = { + // Near face + 0, 1, 1, 2, 2, 3, 3, 0, + // Far face + 4, 5, 5, 6, 6, 7, 7, 4, + // Connecting edges + 0, 4, 1, 5, 2, 6, 3, 7 + }; + + const size_t boxVertexOffset = instancedVertices.size(); + const size_t boxIndexOffset = instancedIndices.size(); + instancedVertices.insert(instancedVertices.end(), boxVertices.begin(), boxVertices.end()); + instancedIndices.insert(instancedIndices.end(), boxIndices.begin(), boxIndices.end()); + + debugRenderInstanceGroups[index].drawIndexedData.indexCount = boxIndicesCount; + debugRenderInstanceGroups[index].drawIndexedData.firstIndex = boxIndexOffset; + debugRenderInstanceGroups[index].drawIndexedData.vertexOffset = static_cast(boxVertexOffset); + debugRenderInstanceGroups[index].drawIndexedData.firstInstance = 0; +} + +void DebugRenderer::setupSphereRendering(const int32_t index) +{ + // Sphere Instance Data Buffer + constexpr uint64_t sphereInstanceBufferSize = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT * sizeof(DebugRendererInstance); + + debugRenderInstanceGroups[index].instanceDescriptorBuffer = resourceManager.createDescriptorBufferUniform(uniformLayout, FRAME_OVERLAP); + for (int32_t i = 0; i < FRAME_OVERLAP; ++i) { + debugRenderInstanceGroups[index].instanceBuffers[i] = resourceManager.createHostSequentialBuffer(sphereInstanceBufferSize); + debugRenderInstanceGroups[index].instanceBufferSizes[i] = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + DescriptorUniformData addressesUniformData{ + .uniformBuffer = debugRenderInstanceGroups[index].instanceBuffers[i], + .allocSize = sphereInstanceBufferSize, + }; + + resourceManager.setupDescriptorBufferUniform(debugRenderInstanceGroups[index].instanceDescriptorBuffer, {addressesUniformData}, i); + } + + debugRenderInstanceGroups[index].instances.reserve(DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT); + + constexpr int32_t rings = SPHERE_DETAIL_MEDIUM.rings; + constexpr int32_t segments = SPHERE_DETAIL_MEDIUM.segments; + constexpr int32_t sphereVertexCount = (rings + 1) * segments; + constexpr int32_t sphereLineCount = rings * segments * 2; // Longitude + latitude lines + constexpr int32_t sphereIndicesCount = sphereLineCount * 2; // 2 indices per line + + instancedVertices.reserve(instancedVertices.size() + sphereVertexCount); + instancedIndices.reserve(instancedIndices.size() + sphereIndicesCount); + + std::vector sphereVertices; + sphereVertices.reserve(sphereVertexCount); + + for (int32_t ring = 0; ring <= rings; ++ring) { + float phi = glm::pi() * static_cast(ring) / static_cast(rings); + for (int32_t segment = 0; segment < segments; ++segment) { + float theta = 2.0f * glm::pi() * static_cast(segment) / static_cast(segments); + + float x = std::sin(phi) * std::cos(theta); + float y = std::cos(phi); + float z = std::sin(phi) * std::sin(theta); + + sphereVertices.push_back({{x, y, z}}); + } + } + + std::vector sphereIndices; + sphereIndices.reserve(sphereIndicesCount); + + for (int32_t ring = 0; ring < rings; ++ring) { + const int32_t ringStart = ring * segments; + const int32_t nextRingStart = (ring + 1) * segments; + for (int32_t segment = 0; segment < segments; ++segment) { + sphereIndices.push_back(ringStart + segment); + sphereIndices.push_back(nextRingStart + segment); + } + } + + for (int32_t ring = 0; ring <= rings; ++ring) { + const int32_t ringStart = ring * segments; + for (int32_t segment = 0; segment < segments; ++segment) { + sphereIndices.push_back(ringStart + segment); + sphereIndices.push_back(ringStart + ((segment + 1) % segments)); + } + } + + const size_t sphereVertexOffset = instancedVertices.size(); + const size_t sphereIndexOffset = instancedIndices.size(); + instancedVertices.insert(instancedVertices.end(), sphereVertices.begin(), sphereVertices.end()); + instancedIndices.insert(instancedIndices.end(), sphereIndices.begin(), sphereIndices.end()); + + debugRenderInstanceGroups[index].drawIndexedData.indexCount = sphereIndicesCount; + debugRenderInstanceGroups[index].drawIndexedData.firstIndex = sphereIndexOffset; + debugRenderInstanceGroups[index].drawIndexedData.vertexOffset = static_cast(sphereVertexOffset); + debugRenderInstanceGroups[index].drawIndexedData.firstInstance = 0; +} + +void DebugRenderer::setupLineRendering() +{ + constexpr uint64_t vertexBufferSize = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT * sizeof(DebugRendererVertexFull); + for (int32_t i{0}; i < FRAME_OVERLAP; i++) { + lineVertexBufferSizes[i] = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + lineVertexBuffers[i] = resourceManager.createHostSequentialBuffer(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + } +} + +void DebugRenderer::setupTriangleRendering() +{ + constexpr uint64_t vertexBufferSize = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT * sizeof(DebugRendererVertexFull); + for (int32_t i{0}; i < FRAME_OVERLAP; i++) { + triangleVertexBufferSizes[i] = DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT; + triangleVertexBuffers[i] = resourceManager.createHostSequentialBuffer(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + } +} +} diff --git a/src/renderer/pipelines/debug/debug_renderer.h b/src/renderer/pipelines/debug/debug_renderer.h new file mode 100644 index 00000000..fa82ab3a --- /dev/null +++ b/src/renderer/pipelines/debug/debug_renderer.h @@ -0,0 +1,128 @@ +// +// Created by William on 2025-04-27. +// + +#ifndef DEBUG_RENDERER_H +#define DEBUG_RENDERER_H + +#include + +#include "debug_renderer_types.h" +#include "src/renderer/renderer_constants.h" +#include "src/renderer/vk_types.h" + +namespace will_engine +{ +class ResourceManager; +} + +namespace will_engine::debug_renderer +{ + +struct DebugRendererPushConstant +{ + int32_t bInstanced{false}; +}; + +/** + * Note: Debug rendering doesn't write to the velocity buffer, so do not contribute to the velocity buffer. As a result, no TAA is expected. + */ +class DebugRenderer +{ +public: + static DebugRenderer* debugRenderer; + static DebugRenderer* get() { return debugRenderer; } + static void set(DebugRenderer* _debugRenderer) { debugRenderer = _debugRenderer; } + + + void setupBoxRendering(int32_t index); + + void setupSphereRendering(int32_t index); + + void setupLineRendering(); + + void setupTriangleRendering(); + + explicit DebugRenderer(ResourceManager& resourceManager); + + ~DebugRenderer(); + +public: + static void drawLine(const glm::vec3& start, const glm::vec3& end, const glm::vec3& color); + + static void drawTriangle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3, const glm::vec3& color); + + static void drawSphere(const glm::vec3& center, float radius, const glm::vec3& color, DebugRendererCategory category = DebugRendererCategory::General); + + static void drawBox(const glm::vec3& center, const glm::vec3& dimensions, const glm::vec3& color, DebugRendererCategory category = DebugRendererCategory::General); + + static void drawBoxMinMax(const glm::vec3& min, const glm::vec3& max, const glm::vec3& color, DebugRendererCategory category = DebugRendererCategory::General); + +private: + void drawLineImpl(const glm::vec3& start, const glm::vec3& end, const glm::vec3& color); + + void drawTriangleImpl(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3, const glm::vec3& color); + + void drawSphereImpl(const glm::vec3& center, float radius, const glm::vec3& color, DebugRendererCategory category = DebugRendererCategory::General); + + void drawBoxImpl(const glm::vec3& center, const glm::vec3& dimensions, const glm::vec3& color, DebugRendererCategory category = DebugRendererCategory::General); + + void drawBoxMinMaxImpl(const glm::vec3& min, const glm::vec3& max, const glm::vec3& color, DebugRendererCategory category = DebugRendererCategory::General); + +public: + void draw(VkCommandBuffer cmd, const DebugRendererDrawInfo& drawInfo); + + void reloadShaders() + { + createPipeline(); + } + +private: + void clear(); + + void createPipeline(); + + VkPipelineLayout instancedPipelineLayout{VK_NULL_HANDLE}; + VkPipelineLayout normalPipelineLayout{VK_NULL_HANDLE}; + VkPipeline instancedLinePipeline{VK_NULL_HANDLE}; + + + /** + * Full refers to vertex format. Also refers to the lack of vertex color in the vertex data + */ + VkPipeline linePipeline{VK_NULL_HANDLE}; + VkPipeline trianglePipeline{VK_NULL_HANDLE}; + +private: + ResourceManager& resourceManager; + + DebugRendererCategory activeCategories{DebugRendererCategory::ALL}; + + // for custom debug draws from Jolt. For primitives use the instanced draws instead. + std::vector lineVertices{}; + std::array lineVertexBufferSizes{0, 0}; + std::array lineVertexBuffers{VK_NULL_HANDLE, VK_NULL_HANDLE}; + + std::vector triangleVertices{}; + std::array triangleVertexBufferSizes{0, 0}; + std::array triangleVertexBuffers{VK_NULL_HANDLE, VK_NULL_HANDLE}; + + VkDescriptorSetLayout uniformLayout{VK_NULL_HANDLE}; + + std::vector instancedVertices{}; + std::vector instancedIndices{}; + AllocatedBuffer instancedVertexBuffer{VK_NULL_HANDLE}; + AllocatedBuffer instancedIndexBuffer{VK_NULL_HANDLE}; + + /** + * 0 = box, 1 = sphere + */ + std::array debugRenderInstanceGroups; + + + + +}; +} + +#endif //DEBUG_RENDERER_H diff --git a/src/renderer/pipelines/debug/debug_renderer_types.h b/src/renderer/pipelines/debug/debug_renderer_types.h new file mode 100644 index 00000000..e844e884 --- /dev/null +++ b/src/renderer/pipelines/debug/debug_renderer_types.h @@ -0,0 +1,119 @@ +// +// Created by William on 2025-04-27. +// + +#ifndef DEBUG_RENDERER_TYPES_H +#define DEBUG_RENDERER_TYPES_H + +#include +#include + +#include "src/renderer/renderer_constants.h" +#include "src/renderer/vk_types.h" +#include "src/renderer/descriptor_buffer/descriptor_buffer_uniform.h" + +namespace will_engine::debug_renderer +{ +static constexpr inline int32_t DEFAULT_DEBUG_RENDERER_INSTANCE_COUNT = 512; +static constexpr inline int32_t BOX_INSTANCE_INDEX = 0; +static constexpr inline int32_t SPHERE_INSTANCE_INDEX = 1; + +struct SphereDetailLevel { + int32_t rings; + int32_t segments; +}; + +static constexpr inline SphereDetailLevel SPHERE_DETAIL_LOW = {4, 8}; +static constexpr inline SphereDetailLevel SPHERE_DETAIL_MEDIUM = {8, 16}; +static constexpr inline SphereDetailLevel SPHERE_DETAIL_HIGH = {16, 32}; + +enum class DebugRendererCategory : uint32_t +{ + None = 0x00000000, // Will always be drawn + Physics = 1 << 0, + Gameplay = 1 << 1, + UI = 1 << 2, + General = 1 << 3, + Navigation = 1 << 4, + AI = 1 << 5, + ALL = 0xFFFFFFFF +}; + +inline DebugRendererCategory operator|(DebugRendererCategory a, DebugRendererCategory b) +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline DebugRendererCategory operator&(DebugRendererCategory a, DebugRendererCategory b) +{ + return static_cast(static_cast(a) & static_cast(b)); +} + +inline DebugRendererCategory operator~(DebugRendererCategory a) +{ + return static_cast(~static_cast(a)); +} + +inline DebugRendererCategory& operator|=(DebugRendererCategory& a, DebugRendererCategory b) +{ + return a = a | b; +} + +inline DebugRendererCategory& operator&=(DebugRendererCategory& a, DebugRendererCategory b) +{ + return a = a & b; +} + +inline bool hasFlag(DebugRendererCategory flags, DebugRendererCategory flag) +{ + return (static_cast(flags) & static_cast(flag)) == static_cast(flag); +} + +struct DebugRendererVertexFull +{ + glm::vec3 position; + glm::vec3 color; +}; + +struct DebugRendererVertex +{ + glm::vec3 position; +}; + +struct DebugRendererInstance +{ + glm::mat4 transform{1.0f}; // Position + scale + glm::vec3 color{0.0f, 1.0f, 0.0f}; + float padding{0.0f}; +}; + +struct DebugRendererDrawInfo +{ + int32_t currentFrameOverlap{}; + VkImageView debugTarget{VK_NULL_HANDLE}; + VkImageView depthTarget{VK_NULL_HANDLE}; + VkDescriptorBufferBindingInfoEXT sceneDataBinding{}; + VkDeviceSize sceneDataOffset{0}; +}; + +struct DrawIndexedData +{ + uint32_t indexCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +}; + + +struct DebugRenderGroup +{ + std::vector instances; + std::array instanceBuffers{VK_NULL_HANDLE, VK_NULL_HANDLE}; + std::array instanceBufferSizes{0, 0}; + DrawIndexedData drawIndexedData{}; + DescriptorBufferUniform instanceDescriptorBuffer; + +}; +} + +#endif //DEBUG_RENDERER_TYPES_H diff --git a/src/renderer/pipelines/geometry/deferred_mrt/deferred_mrt_pipeline.cpp b/src/renderer/pipelines/geometry/deferred_mrt/deferred_mrt_pipeline.cpp index 8ff34193..56888f64 100644 --- a/src/renderer/pipelines/geometry/deferred_mrt/deferred_mrt_pipeline.cpp +++ b/src/renderer/pipelines/geometry/deferred_mrt/deferred_mrt_pipeline.cpp @@ -34,8 +34,8 @@ will_engine::deferred_mrt::DeferredMrtPipeline::DeferredMrtPipeline(ResourceMana will_engine::deferred_mrt::DeferredMrtPipeline::~DeferredMrtPipeline() { - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(pipeline); } void will_engine::deferred_mrt::DeferredMrtPipeline::draw(VkCommandBuffer cmd, const DeferredMrtDrawInfo& drawInfo) const @@ -95,12 +95,11 @@ void will_engine::deferred_mrt::DeferredMrtPipeline::draw(VkCommandBuffer cmd, c scissor.extent.width = RENDER_EXTENTS.width; scissor.extent.height = RENDER_EXTENTS.height; vkCmdSetScissor(cmd, 0, 1, &scissor); - constexpr VkDeviceSize zeroOffset{0}; for (RenderObject* renderObject : drawInfo.renderObjects) { if (!renderObject->canDraw()) { continue; } - std::array descriptorBufferBindingInfos{ + std::array descriptorBufferBindingInfos{ drawInfo.sceneDataBinding, renderObject->getAddressesDescriptorBuffer().getDescriptorBufferBindingInfo(), renderObject->getTextureDescriptorBuffer().getDescriptorBufferBindingInfo(), @@ -110,7 +109,7 @@ void will_engine::deferred_mrt::DeferredMrtPipeline::draw(VkCommandBuffer cmd, c constexpr std::array indices{0, 1, 2}; - std::array offsets{ + std::array offsets{ drawInfo.sceneDataOffset, renderObject->getAddressesDescriptorBuffer().getDescriptorBufferSize() * drawInfo.currentFrameOverlap, ZERO_DEVICE_SIZE @@ -133,7 +132,7 @@ void will_engine::deferred_mrt::DeferredMrtPipeline::draw(VkCommandBuffer cmd, c void will_engine::deferred_mrt::DeferredMrtPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/deferredMrt.vert"); VkShaderModule fragShader = resourceManager.createShaderModule("shaders/deferredMrt.frag"); @@ -179,10 +178,10 @@ void will_engine::deferred_mrt::DeferredMrtPipeline::createPipeline() renderPipelineBuilder.disableMultisampling(); renderPipelineBuilder.disableBlending(); renderPipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); - renderPipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_FORMAT); + renderPipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_STENCIL_FORMAT); renderPipelineBuilder.setupPipelineLayout(pipelineLayout); pipeline = resourceManager.createRenderPipeline(renderPipelineBuilder); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); } diff --git a/src/renderer/pipelines/geometry/deferred_resolve/deferred_resolve_pipeline.cpp b/src/renderer/pipelines/geometry/deferred_resolve/deferred_resolve_pipeline.cpp index 357d65fb..fa10734b 100644 --- a/src/renderer/pipelines/geometry/deferred_resolve/deferred_resolve_pipeline.cpp +++ b/src/renderer/pipelines/geometry/deferred_resolve/deferred_resolve_pipeline.cpp @@ -46,9 +46,9 @@ will_engine::deferred_resolve::DeferredResolvePipeline::DeferredResolvePipeline( will_engine::deferred_resolve::DeferredResolvePipeline::~DeferredResolvePipeline() { - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyDescriptorBuffer(resolveDescriptorBuffer); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(pipeline); + resourceManager.destroy(resolveDescriptorBuffer); } void will_engine::deferred_resolve::DeferredResolvePipeline::setupDescriptorBuffer(const DeferredResolveDescriptor& drawInfo) @@ -162,7 +162,7 @@ void will_engine::deferred_resolve::DeferredResolvePipeline::draw(VkCommandBuffe void will_engine::deferred_resolve::DeferredResolvePipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule deferredResolveShader = resourceManager.createShaderModule("shaders/deferredResolve.comp"); VkPipelineShaderStageCreateInfo stageInfo = {}; @@ -180,5 +180,5 @@ void will_engine::deferred_resolve::DeferredResolvePipeline::createPipeline() pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; pipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(deferredResolveShader); + resourceManager.destroy(deferredResolveShader); } diff --git a/src/renderer/pipelines/geometry/environment/environment_pipeline.cpp b/src/renderer/pipelines/geometry/environment/environment_pipeline.cpp index 7acab329..c705cbfb 100644 --- a/src/renderer/pipelines/geometry/environment/environment_pipeline.cpp +++ b/src/renderer/pipelines/geometry/environment/environment_pipeline.cpp @@ -30,8 +30,8 @@ will_engine::environment_pipeline::EnvironmentPipeline::EnvironmentPipeline(Reso will_engine::environment_pipeline::EnvironmentPipeline::~EnvironmentPipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); } void will_engine::environment_pipeline::EnvironmentPipeline::draw(VkCommandBuffer cmd, const EnvironmentDrawInfo& drawInfo) const @@ -108,7 +108,7 @@ void will_engine::environment_pipeline::EnvironmentPipeline::draw(VkCommandBuffe void will_engine::environment_pipeline::EnvironmentPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/environment/environment.vert"); VkShaderModule fragShader = resourceManager.createShaderModule("shaders/environment/environment.frag"); @@ -119,12 +119,12 @@ void will_engine::environment_pipeline::EnvironmentPipeline::createPipeline() pipelineBuilder.disableMultisampling(); pipelineBuilder.disableBlending(); pipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); - pipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_FORMAT); + pipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_STENCIL_FORMAT); pipelineBuilder.setupPipelineLayout(pipelineLayout); pipeline = resourceManager.createRenderPipeline(pipelineBuilder); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); } diff --git a/src/renderer/pipelines/geometry/terrain/terrain_pipeline.cpp b/src/renderer/pipelines/geometry/terrain/terrain_pipeline.cpp index cb112f2f..7960d4c2 100644 --- a/src/renderer/pipelines/geometry/terrain/terrain_pipeline.cpp +++ b/src/renderer/pipelines/geometry/terrain/terrain_pipeline.cpp @@ -39,9 +39,9 @@ will_engine::terrain::TerrainPipeline::TerrainPipeline(ResourceManager& resource will_engine::terrain::TerrainPipeline::~TerrainPipeline() { - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipeline(linePipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(pipeline); + resourceManager.destroy(linePipeline); } void will_engine::terrain::TerrainPipeline::draw(VkCommandBuffer cmd, const TerrainDrawInfo& drawInfo) const @@ -143,7 +143,7 @@ void will_engine::terrain::TerrainPipeline::draw(VkCommandBuffer cmd, const Terr void will_engine::terrain::TerrainPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/terrain/terrain.vert"); VkShaderModule tescShader = resourceManager.createShaderModule("shaders/terrain/terrain.tesc"); VkShaderModule teseShader = resourceManager.createShaderModule("shaders/terrain/terrain.tese"); @@ -184,20 +184,20 @@ void will_engine::terrain::TerrainPipeline::createPipeline() pipelineBuilder.disableMultisampling(); pipelineBuilder.disableBlending(); pipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); - pipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_FORMAT); + pipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_STENCIL_FORMAT); pipelineBuilder.setupPipelineLayout(pipelineLayout); pipelineBuilder.setupTessellation(4); pipeline = resourceManager.createRenderPipeline(pipelineBuilder, {VK_DYNAMIC_STATE_DEPTH_BIAS}); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(tescShader); - resourceManager.destroyShaderModule(teseShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(tescShader); + resourceManager.destroy(teseShader); + resourceManager.destroy(fragShader); } void will_engine::terrain::TerrainPipeline::createLinePipeline() { - resourceManager.destroyPipeline(linePipeline); + resourceManager.destroy(linePipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/terrain/terrain.vert"); VkShaderModule tescShader = resourceManager.createShaderModule("shaders/terrain/terrain.tesc"); VkShaderModule teseShader = resourceManager.createShaderModule("shaders/terrain/terrain.tese"); @@ -238,13 +238,13 @@ void will_engine::terrain::TerrainPipeline::createLinePipeline() pipelineBuilder.disableMultisampling(); pipelineBuilder.disableBlending(); pipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_GREATER_OR_EQUAL); - pipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_FORMAT); + pipelineBuilder.setupRenderer({NORMAL_FORMAT, ALBEDO_FORMAT, PBR_FORMAT, VELOCITY_FORMAT}, DEPTH_STENCIL_FORMAT); pipelineBuilder.setupPipelineLayout(pipelineLayout); pipelineBuilder.setupTessellation(4); linePipeline = resourceManager.createRenderPipeline(pipelineBuilder, {VK_DYNAMIC_STATE_DEPTH_BIAS}); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(tescShader); - resourceManager.destroyShaderModule(teseShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(tescShader); + resourceManager.destroy(teseShader); + resourceManager.destroy(fragShader); } diff --git a/src/renderer/pipelines/geometry/transparent_pipeline/transparent_pipeline.cpp b/src/renderer/pipelines/geometry/transparent_pipeline/transparent_pipeline.cpp index 80283e87..71cf394e 100644 --- a/src/renderer/pipelines/geometry/transparent_pipeline/transparent_pipeline.cpp +++ b/src/renderer/pipelines/geometry/transparent_pipeline/transparent_pipeline.cpp @@ -101,15 +101,15 @@ TransparentPipeline::TransparentPipeline(ResourceManager& resourceManager, TransparentPipeline::~TransparentPipeline() { - resourceManager.destroyImage(accumulationImage); - resourceManager.destroyImage(revealageImage); - resourceManager.destroyImage(debugImage); - resourceManager.destroyPipelineLayout(accumulationPipelineLayout); - resourceManager.destroyPipeline(accumulationPipeline); - resourceManager.destroyDescriptorSetLayout(compositeDescriptorSetLayout); - resourceManager.destroyPipelineLayout(compositePipelineLayout); - resourceManager.destroyPipeline(compositePipeline); - resourceManager.destroyDescriptorBuffer(compositeDescriptorBuffer); + resourceManager.destroy(accumulationImage); + resourceManager.destroy(revealageImage); + resourceManager.destroy(debugImage); + resourceManager.destroy(accumulationPipelineLayout); + resourceManager.destroy(accumulationPipeline); + resourceManager.destroy(compositeDescriptorSetLayout); + resourceManager.destroy(compositePipelineLayout); + resourceManager.destroy(compositePipeline); + resourceManager.destroy(compositeDescriptorBuffer); } void TransparentPipeline::drawAccumulate(VkCommandBuffer cmd, const TransparentAccumulateDrawInfo& drawInfo) const @@ -119,11 +119,11 @@ void TransparentPipeline::drawAccumulate(VkCommandBuffer cmd, const TransparentA label.pLabelName = "Transparent Accumulation Pass (Render Objects)"; vkCmdBeginDebugUtilsLabelEXT(cmd, &label); - vk_helpers::transitionImage(cmd, accumulationImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, accumulationImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, revealageImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, revealageImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, debugImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, debugImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); @@ -219,11 +219,11 @@ void TransparentPipeline::drawAccumulate(VkCommandBuffer cmd, const TransparentA vkCmdEndRendering(cmd); - vk_helpers::transitionImage(cmd, accumulationImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, accumulationImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, revealageImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, revealageImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, debugImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, debugImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); vkCmdEndDebugUtilsLabelEXT(cmd); @@ -297,7 +297,7 @@ void TransparentPipeline::drawComposite(VkCommandBuffer cmd, const TransparentCo void TransparentPipeline::createAccumulationPipeline() { - resourceManager.destroyPipeline(accumulationPipeline); + resourceManager.destroy(accumulationPipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/transparent.vert"); VkShaderModule fragShader = resourceManager.createShaderModule("shaders/transparent.frag"); @@ -368,17 +368,17 @@ void TransparentPipeline::createAccumulationPipeline() pipelineBuilder.setupBlending(blendAttachmentStates); pipelineBuilder.enableDepthTest(false, VK_COMPARE_OP_GREATER); - pipelineBuilder.setupRenderer({accumulationImageFormat, revealageImageFormat, debugImageFormat}, DEPTH_FORMAT); + pipelineBuilder.setupRenderer({accumulationImageFormat, revealageImageFormat, debugImageFormat}, DEPTH_STENCIL_FORMAT); pipelineBuilder.setupPipelineLayout(accumulationPipelineLayout); accumulationPipeline = resourceManager.createRenderPipeline(pipelineBuilder); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); } void TransparentPipeline::createCompositePipeline() { - resourceManager.destroyPipeline(compositePipeline); + resourceManager.destroy(compositePipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/transparentComposite.vert"); VkShaderModule fragShader = resourceManager.createShaderModule("shaders/transparentComposite.frag"); @@ -400,24 +400,13 @@ void TransparentPipeline::createCompositePipeline() blendAttachmentStates[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - // blendAttachmentStates[0].blendEnable = VK_TRUE; - // blendAttachmentStates[0].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - // blendAttachmentStates[0].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - // blendAttachmentStates[0].colorBlendOp = VK_BLEND_OP_ADD; - // blendAttachmentStates[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - // blendAttachmentStates[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - // blendAttachmentStates[0].alphaBlendOp = VK_BLEND_OP_ADD; - // blendAttachmentStates[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - // VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - pipelineBuilder.setupBlending(blendAttachmentStates); pipelineBuilder.disableDepthTest(); - pipelineBuilder.setupRenderer({DRAW_FORMAT}, VK_FORMAT_UNDEFINED); + pipelineBuilder.setupRenderer({DRAW_FORMAT}); pipelineBuilder.setupPipelineLayout(compositePipelineLayout); compositePipeline = resourceManager.createRenderPipeline(pipelineBuilder); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); } } diff --git a/src/renderer/pipelines/post/post_process/post_process_pipeline.cpp b/src/renderer/pipelines/post/post_process/post_process_pipeline.cpp index 33c10344..1788eccd 100644 --- a/src/renderer/pipelines/post/post_process/post_process_pipeline.cpp +++ b/src/renderer/pipelines/post/post_process/post_process_pipeline.cpp @@ -47,10 +47,10 @@ will_engine::post_process_pipeline::PostProcessPipeline::PostProcessPipeline(Res will_engine::post_process_pipeline::PostProcessPipeline::~PostProcessPipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyDescriptorSetLayout(descriptorSetLayout); - resourceManager.destroyDescriptorBuffer(descriptorBuffer); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(descriptorSetLayout); + resourceManager.destroy(descriptorBuffer); } void will_engine::post_process_pipeline::PostProcessPipeline::setupDescriptorBuffer(const PostProcessDescriptor& bufferInfo) @@ -113,7 +113,7 @@ void will_engine::post_process_pipeline::PostProcessPipeline::draw(VkCommandBuff void will_engine::post_process_pipeline::PostProcessPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/postProcess.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -131,5 +131,5 @@ void will_engine::post_process_pipeline::PostProcessPipeline::createPipeline() pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; pipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } diff --git a/src/renderer/pipelines/post/temporal_antialiasing/temporal_antialiasing_pipeline.cpp b/src/renderer/pipelines/post/temporal_antialiasing/temporal_antialiasing_pipeline.cpp index 54521d61..0ed7a2b2 100644 --- a/src/renderer/pipelines/post/temporal_antialiasing/temporal_antialiasing_pipeline.cpp +++ b/src/renderer/pipelines/post/temporal_antialiasing/temporal_antialiasing_pipeline.cpp @@ -47,10 +47,10 @@ will_engine::temporal_antialiasing_pipeline::TemporalAntialiasingPipeline::Tempo will_engine::temporal_antialiasing_pipeline::TemporalAntialiasingPipeline::~TemporalAntialiasingPipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyDescriptorSetLayout(descriptorSetLayout); - resourceManager.destroyDescriptorBuffer(descriptorBuffer); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(descriptorSetLayout); + resourceManager.destroy(descriptorBuffer); } void will_engine::temporal_antialiasing_pipeline::TemporalAntialiasingPipeline::setupDescriptorBuffer(const TemporalAntialiasingDescriptor& descriptor) @@ -134,7 +134,7 @@ void will_engine::temporal_antialiasing_pipeline::TemporalAntialiasingPipeline:: void will_engine::temporal_antialiasing_pipeline::TemporalAntialiasingPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/taa.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -152,5 +152,5 @@ void will_engine::temporal_antialiasing_pipeline::TemporalAntialiasingPipeline:: pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; pipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } diff --git a/src/renderer/pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.cpp b/src/renderer/pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.cpp index 36b5623f..0cb928c7 100644 --- a/src/renderer/pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.cpp +++ b/src/renderer/pipelines/shadows/cascaded_shadow_map/cascaded_shadow_map.cpp @@ -143,22 +143,22 @@ will_engine::cascaded_shadows::CascadedShadowMap::CascadedShadowMap(ResourceMana will_engine::cascaded_shadows::CascadedShadowMap::~CascadedShadowMap() { for (CascadeShadowMapData& cascadeShadowMapData : shadowMaps) { - resourceManager.destroyImage(cascadeShadowMapData.depthShadowMap); + resourceManager.destroy(cascadeShadowMapData.depthShadowMap); cascadeShadowMapData.depthShadowMap = {}; } - resourceManager.destroyDescriptorSetLayout(cascadedShadowMapUniformLayout); - resourceManager.destroyDescriptorSetLayout(cascadedShadowMapSamplerLayout); + resourceManager.destroy(cascadedShadowMapUniformLayout); + resourceManager.destroy(cascadedShadowMapSamplerLayout); for (int32_t i = 0; i < FRAME_OVERLAP; ++i) { - resourceManager.destroyBuffer(cascadedShadowMapDatas[i]); + resourceManager.destroy(cascadedShadowMapDatas[i]); } - resourceManager.destroyDescriptorBuffer(cascadedShadowMapDescriptorBufferSampler); - resourceManager.destroyDescriptorBuffer(cascadedShadowMapDescriptorBufferUniform); - resourceManager.destroySampler(sampler); - resourceManager.destroyPipeline(renderObjectPipeline); - resourceManager.destroyPipelineLayout(renderObjectPipelineLayout); - resourceManager.destroyPipeline(terrainPipeline); - resourceManager.destroyPipelineLayout(terrainPipelineLayout); + resourceManager.destroy(cascadedShadowMapDescriptorBufferSampler); + resourceManager.destroy(cascadedShadowMapDescriptorBufferUniform); + resourceManager.destroy(sampler); + resourceManager.destroy(renderObjectPipeline); + resourceManager.destroy(renderObjectPipelineLayout); + resourceManager.destroy(terrainPipeline); + resourceManager.destroy(terrainPipelineLayout); } void will_engine::cascaded_shadows::CascadedShadowMap::update(const DirectionalLight& mainLight, const Camera* camera, @@ -206,7 +206,7 @@ void will_engine::cascaded_shadows::CascadedShadowMap::draw(VkCommandBuffer cmd, continue; } - vk_helpers::transitionImage(cmd, cascadeShadowMapData.depthShadowMap.image, VK_IMAGE_LAYOUT_UNDEFINED, + vk_helpers::imageBarrier(cmd, cascadeShadowMapData.depthShadowMap.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); @@ -352,7 +352,7 @@ void will_engine::cascaded_shadows::CascadedShadowMap::draw(VkCommandBuffer cmd, vkCmdEndRendering(cmd); } - vk_helpers::transitionImage(cmd, cascadeShadowMapData.depthShadowMap.image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + vk_helpers::imageBarrier(cmd, cascadeShadowMapData.depthShadowMap.image, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); } @@ -421,7 +421,7 @@ glm::mat4 will_engine::cascaded_shadows::CascadedShadowMap::getLightSpaceMatrix( void will_engine::cascaded_shadows::CascadedShadowMap::createRenderObjectPipeline() { - resourceManager.destroyPipeline(renderObjectPipeline); + resourceManager.destroy(renderObjectPipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/shadows/shadow_pass.vert"); VkShaderModule fragShader = resourceManager.createShaderModule("shaders/shadows/shadow_pass.frag"); @@ -447,17 +447,17 @@ void will_engine::cascaded_shadows::CascadedShadowMap::createRenderObjectPipelin pipelineBuilder.disableMultisampling(); pipelineBuilder.disableBlending(); pipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_LESS_OR_EQUAL); - pipelineBuilder.setupRenderer({}, DEPTH_FORMAT); + pipelineBuilder.setupRenderer({}, CASCADE_DEPTH_FORMAT); pipelineBuilder.setupPipelineLayout(renderObjectPipelineLayout); renderObjectPipeline = resourceManager.createRenderPipeline(pipelineBuilder, {VK_DYNAMIC_STATE_DEPTH_BIAS}); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(fragShader); } void will_engine::cascaded_shadows::CascadedShadowMap::createTerrainPipeline() { - resourceManager.destroyPipeline(terrainPipeline); + resourceManager.destroy(terrainPipeline); VkShaderModule vertShader = resourceManager.createShaderModule("shaders/shadows/terrain_shadow_pass.vert"); VkShaderModule tescShader = resourceManager.createShaderModule("shaders/shadows/terrain_shadow_pass.tesc"); @@ -485,15 +485,15 @@ void will_engine::cascaded_shadows::CascadedShadowMap::createTerrainPipeline() pipelineBuilder.disableMultisampling(); pipelineBuilder.disableBlending(); pipelineBuilder.enableDepthTest(true, VK_COMPARE_OP_LESS_OR_EQUAL); - pipelineBuilder.setupRenderer({}, DEPTH_FORMAT); + pipelineBuilder.setupRenderer({}, CASCADE_DEPTH_FORMAT); pipelineBuilder.setupPipelineLayout(terrainPipelineLayout); pipelineBuilder.setupTessellation(4); terrainPipeline = resourceManager.createRenderPipeline(pipelineBuilder, {VK_DYNAMIC_STATE_DEPTH_BIAS}); - resourceManager.destroyShaderModule(vertShader); - resourceManager.destroyShaderModule(tescShader); - resourceManager.destroyShaderModule(teseShader); - resourceManager.destroyShaderModule(fragShader); + resourceManager.destroy(vertShader); + resourceManager.destroy(tescShader); + resourceManager.destroy(teseShader); + resourceManager.destroy(fragShader); } void will_engine::cascaded_shadows::CascadedShadowMap::generateSplits() diff --git a/src/renderer/pipelines/shadows/contact_shadow/contact_shadows_pipeline.cpp b/src/renderer/pipelines/shadows/contact_shadow/contact_shadows_pipeline.cpp index 16c359d6..148e3735 100644 --- a/src/renderer/pipelines/shadows/contact_shadow/contact_shadows_pipeline.cpp +++ b/src/renderer/pipelines/shadows/contact_shadow/contact_shadows_pipeline.cpp @@ -79,15 +79,15 @@ ContactShadowsPipeline::ContactShadowsPipeline(ResourceManager& resourceManager) ContactShadowsPipeline::~ContactShadowsPipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); - resourceManager.destroyDescriptorSetLayout(descriptorSetLayout); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); + resourceManager.destroy(descriptorSetLayout); - resourceManager.destroySampler(depthSampler); + resourceManager.destroy(depthSampler); - resourceManager.destroyImage(contactShadowImage); - resourceManager.destroyImage(debugImage); - resourceManager.destroyDescriptorBuffer(descriptorBufferSampler); + resourceManager.destroy(contactShadowImage); + resourceManager.destroy(debugImage); + resourceManager.destroy(descriptorBufferSampler); } void ContactShadowsPipeline::setupDescriptorBuffer(const VkImageView& depthImageView) @@ -118,7 +118,7 @@ void ContactShadowsPipeline::setupDescriptorBuffer(const VkImageView& depthImage void ContactShadowsPipeline::draw(VkCommandBuffer cmd, const ContactShadowsDrawInfo& drawInfo) { - vk_helpers::transitionImage(cmd, debugImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, debugImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); vk_helpers::clearColorImage(cmd, VK_IMAGE_ASPECT_COLOR_BIT, contactShadowImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); if (!drawInfo.bIsEnabled) { @@ -154,7 +154,7 @@ void ContactShadowsPipeline::draw(VkCommandBuffer cmd, const ContactShadowsDrawI void ContactShadowsPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/shadows/contact_shadow_pass.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -172,7 +172,7 @@ void ContactShadowsPipeline::createPipeline() pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; pipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } DispatchList ContactShadowsPipeline::buildDispatchList(const Camera* camera, const DirectionalLight& mainLight) diff --git a/src/renderer/pipelines/shadows/ground_truth_ambient_occlusion/ground_truth_ambient_occlusion_pipeline.cpp b/src/renderer/pipelines/shadows/ground_truth_ambient_occlusion/ground_truth_ambient_occlusion_pipeline.cpp index 080d707e..c365595e 100644 --- a/src/renderer/pipelines/shadows/ground_truth_ambient_occlusion/ground_truth_ambient_occlusion_pipeline.cpp +++ b/src/renderer/pipelines/shadows/ground_truth_ambient_occlusion/ground_truth_ambient_occlusion_pipeline.cpp @@ -226,42 +226,42 @@ will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::GroundTruth will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::~GroundTruthAmbientOcclusionPipeline() { // Debug Resources - resourceManager.destroyImage(debugImage); + resourceManager.destroy(debugImage); // Depth Prefilter Resources - resourceManager.destroyDescriptorSetLayout(depthPrefilterSetLayout); - resourceManager.destroyPipelineLayout(depthPrefilterPipelineLayout); - resourceManager.destroyPipeline(depthPrefilterPipeline); + resourceManager.destroy(depthPrefilterSetLayout); + resourceManager.destroy(depthPrefilterPipelineLayout); + resourceManager.destroy(depthPrefilterPipeline); for (int32_t i = 0; i < DEPTH_PREFILTER_MIP_COUNT; ++i) { - resourceManager.destroyImageView(depthPrefilterImageViews[i]); + resourceManager.destroy(depthPrefilterImageViews[i]); } - resourceManager.destroyImage(depthPrefilterImage); - resourceManager.destroySampler(depthSampler); + resourceManager.destroy(depthPrefilterImage); + resourceManager.destroy(depthSampler); - resourceManager.destroyDescriptorBuffer(depthPrefilterDescriptorBuffer); + resourceManager.destroy(depthPrefilterDescriptorBuffer); // AO Resources - resourceManager.destroyDescriptorSetLayout(ambientOcclusionSetLayout); - resourceManager.destroyPipelineLayout(ambientOcclusionPipelineLayout); - resourceManager.destroyPipeline(ambientOcclusionPipeline); + resourceManager.destroy(ambientOcclusionSetLayout); + resourceManager.destroy(ambientOcclusionPipelineLayout); + resourceManager.destroy(ambientOcclusionPipeline); - resourceManager.destroySampler(depthPrefilterSampler); - resourceManager.destroySampler(normalsSampler); - resourceManager.destroyImage(ambientOcclusionImage); - resourceManager.destroyImage(edgeDataImage); + resourceManager.destroy(depthPrefilterSampler); + resourceManager.destroy(normalsSampler); + resourceManager.destroy(ambientOcclusionImage); + resourceManager.destroy(edgeDataImage); - resourceManager.destroyDescriptorBuffer(ambientOcclusionDescriptorBuffer); + resourceManager.destroy(ambientOcclusionDescriptorBuffer); // Spatial Filtering Resources - resourceManager.destroyDescriptorSetLayout(spatialFilteringSetLayout); - resourceManager.destroyPipelineLayout(spatialFilteringPipelineLayout); - resourceManager.destroyPipeline(spatialFilteringPipeline); + resourceManager.destroy(spatialFilteringSetLayout); + resourceManager.destroy(spatialFilteringPipelineLayout); + resourceManager.destroy(spatialFilteringPipeline); - resourceManager.destroyImage(denoisedFinalAO); + resourceManager.destroy(denoisedFinalAO); - resourceManager.destroyDescriptorBuffer(spatialFilteringDescriptorBuffer); + resourceManager.destroy(spatialFilteringDescriptorBuffer); } void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::setupDepthPrefilterDescriptorBuffer(const VkImageView& depthImageView) @@ -388,14 +388,14 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::draw(V drawInfo.push.noiseIndex = GTAO_DENOISE_PASSES > 0 ? drawInfo.currentFrame % 64 : 0; - vk_helpers::transitionImage(cmd, debugImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, debugImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); vk_helpers::clearColorImage(cmd, VK_IMAGE_ASPECT_COLOR_BIT, depthPrefilterImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); if (!drawInfo.bEnabled) { vk_helpers::clearColorImage(cmd, VK_IMAGE_ASPECT_COLOR_BIT, denoisedFinalAO.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, {1.0f, 1.0f, 1.0f, 1.0f}); - vk_helpers::transitionImage(cmd, debugImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, debugImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); return; } @@ -420,9 +420,9 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::draw(V vkCmdDispatch(cmd, x, y, 1); } - vk_helpers::transitionImage(cmd, depthPrefilterImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, depthPrefilterImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, ambientOcclusionImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, ambientOcclusionImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); // Ambient Occlusion { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, ambientOcclusionPipeline); @@ -444,9 +444,9 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::draw(V } - vk_helpers::transitionImage(cmd, ambientOcclusionImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, ambientOcclusionImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, denoisedFinalAO.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + vk_helpers::imageBarrier(cmd, denoisedFinalAO.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); // Spatial Filtering { @@ -469,11 +469,11 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::draw(V vkCmdDispatch(cmd, x, y, 1); } - vk_helpers::transitionImage(cmd, denoisedFinalAO.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, denoisedFinalAO.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - vk_helpers::transitionImage(cmd, debugImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, debugImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); vkCmdEndDebugUtilsLabelEXT(cmd); @@ -488,7 +488,7 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::reload void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::createDepthPrefilterPipeline() { - resourceManager.destroyPipeline(depthPrefilterPipeline); + resourceManager.destroy(depthPrefilterPipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/ambient_occlusion/ground_truth/gtao_depth_prefilter.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -506,12 +506,12 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::create pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; depthPrefilterPipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::createAmbientOcclusionPipeline() { - resourceManager.destroyPipeline(ambientOcclusionPipeline); + resourceManager.destroy(ambientOcclusionPipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/ambient_occlusion/ground_truth/gtao_main_pass.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -529,12 +529,12 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::create pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; ambientOcclusionPipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::createSpatialFilteringPipeline() { - resourceManager.destroyPipeline(spatialFilteringPipeline); + resourceManager.destroy(spatialFilteringPipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/ambient_occlusion/ground_truth/gtao_spatial_filter.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -552,5 +552,5 @@ void will_engine::ambient_occlusion::GroundTruthAmbientOcclusionPipeline::create pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; spatialFilteringPipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } diff --git a/src/renderer/pipelines/visibility_pass/visibility_pass_pipeline.cpp b/src/renderer/pipelines/visibility_pass/visibility_pass_pipeline.cpp index d2c3223c..86ae01be 100644 --- a/src/renderer/pipelines/visibility_pass/visibility_pass_pipeline.cpp +++ b/src/renderer/pipelines/visibility_pass/visibility_pass_pipeline.cpp @@ -39,8 +39,8 @@ will_engine::visibility_pass_pipeline::VisibilityPassPipeline::VisibilityPassPip will_engine::visibility_pass_pipeline::VisibilityPassPipeline::~VisibilityPassPipeline() { - resourceManager.destroyPipeline(pipeline); - resourceManager.destroyPipelineLayout(pipelineLayout); + resourceManager.destroy(pipeline); + resourceManager.destroy(pipelineLayout); } void will_engine::visibility_pass_pipeline::VisibilityPassPipeline::draw(VkCommandBuffer cmd, const VisibilityPassDrawInfo& drawInfo) const @@ -86,7 +86,7 @@ void will_engine::visibility_pass_pipeline::VisibilityPassPipeline::draw(VkComma vkCmdDispatch(cmd, static_cast(std::ceil(static_cast(renderObject->getOpaqueDrawIndirectCommandCount()) / 64.0f)), 1, 1); - vk_helpers::synchronizeUniform(cmd, renderObject->getOpaqueIndirectBuffer(drawInfo.currentFrameOverlap), + vk_helpers::uniformBarrier(cmd, renderObject->getOpaqueIndirectBuffer(drawInfo.currentFrameOverlap), VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT, VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT); } @@ -97,7 +97,7 @@ void will_engine::visibility_pass_pipeline::VisibilityPassPipeline::draw(VkComma void will_engine::visibility_pass_pipeline::VisibilityPassPipeline::createPipeline() { - resourceManager.destroyPipeline(pipeline); + resourceManager.destroy(pipeline); VkShaderModule computeShader = resourceManager.createShaderModule("shaders/visibility_pass.comp"); VkPipelineShaderStageCreateInfo stageInfo{}; @@ -115,5 +115,5 @@ void will_engine::visibility_pass_pipeline::VisibilityPassPipeline::createPipeli pipelineInfo.flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; pipeline = resourceManager.createComputePipeline(pipelineInfo); - resourceManager.destroyShaderModule(computeShader); + resourceManager.destroy(computeShader); } diff --git a/src/renderer/renderer_constants.h b/src/renderer/renderer_constants.h index e77c7791..d03df0ef 100644 --- a/src/renderer/renderer_constants.h +++ b/src/renderer/renderer_constants.h @@ -5,23 +5,37 @@ #ifndef RENDERER_CONSTANTS_H #define RENDERER_CONSTANTS_H #include + namespace will_engine { constexpr int32_t FRAME_OVERLAP = 2; constexpr char ENGINE_NAME[] = "Will Engine"; constexpr bool USING_REVERSED_DEPTH_BUFFER = true; constexpr VkDeviceSize ZERO_DEVICE_SIZE = 0; -//constexpr VkExtent2D RENDER_EXTENTS{1920, 1080}; -constexpr VkExtent2D RENDER_EXTENTS{2140, 1440}; +constexpr VkExtent2D RENDER_EXTENTS{1920, 1080}; +//constexpr VkExtent2D RENDER_EXTENTS{2560 , 1440}; //constexpr VkExtent2D RENDER_EXTENTS{3840, 2160}; + constexpr float RENDER_EXTENT_WIDTH{RENDER_EXTENTS.width}; constexpr float RENDER_EXTENT_HEIGHT{RENDER_EXTENTS.height}; + +// Be careful, environment map is in HDR format, so non-float formats for draw image won't work constexpr VkFormat DRAW_FORMAT{VK_FORMAT_R16G16B16A16_SFLOAT}; + +constexpr VkFormat DEPTH_STENCIL_FORMAT{VK_FORMAT_D32_SFLOAT_S8_UINT}; constexpr VkFormat DEPTH_FORMAT{VK_FORMAT_D32_SFLOAT}; +constexpr VkFormat STENCIL_FORMAT{VK_FORMAT_S8_UINT}; + +constexpr bool NORMAL_REMAP{true}; +constexpr VkFormat NORMAL_FORMAT = NORMAL_REMAP ? VK_FORMAT_A2R10G10B10_UNORM_PACK32 : VK_FORMAT_R16G16B16A16_SNORM; + constexpr VkFormat VELOCITY_FORMAT{VK_FORMAT_R16G16_SFLOAT}; -constexpr VkFormat NORMAL_FORMAT{VK_FORMAT_R16G16B16A16_SNORM}; -// Be careful, environment map is in HDR format, so non-float formats wont work + +constexpr VkFormat DEBUG_FORMAT{VK_FORMAT_R8G8B8A8_SNORM}; + +// Be careful, environment map is in HDR format, so non-float formats for albedo won't work constexpr VkFormat ALBEDO_FORMAT{VK_FORMAT_R16G16B16A16_SFLOAT}; + constexpr VkFormat PBR_FORMAT{VK_FORMAT_R8G8B8A8_UNORM}; } diff --git a/src/renderer/resource_manager.cpp b/src/renderer/resource_manager.cpp index be54a45a..e669bbbe 100644 --- a/src/renderer/resource_manager.cpp +++ b/src/renderer/resource_manager.cpp @@ -168,19 +168,19 @@ will_engine::ResourceManager::~ResourceManager() { if (context.device == VK_NULL_HANDLE) { return; } - destroyImage(whiteImage); - destroyImage(errorCheckerboardImage); - destroySampler(defaultSamplerNearest); - destroySampler(defaultSamplerLinear); - destroySampler(defaultSamplerMipMappedLinear); - destroyDescriptorSetLayout(emptyDescriptorSetLayout); - destroyDescriptorSetLayout(sceneDataLayout); - destroyDescriptorSetLayout(frustumCullLayout); - destroyDescriptorSetLayout(addressesLayout); - destroyDescriptorSetLayout(texturesLayout); - destroyDescriptorSetLayout(renderTargetsLayout); - destroyDescriptorSetLayout(terrainTexturesLayout); - destroyDescriptorSetLayout(terrainUniformLayout); + destroy(whiteImage); + destroy(errorCheckerboardImage); + destroy(defaultSamplerNearest); + destroy(defaultSamplerLinear); + destroy(defaultSamplerMipMappedLinear); + destroy(emptyDescriptorSetLayout); + destroy(sceneDataLayout); + destroy(frustumCullLayout); + destroy(addressesLayout); + destroy(texturesLayout); + destroy(renderTargetsLayout); + destroy(terrainTexturesLayout); + destroy(terrainUniformLayout); flushDestructionQueue(); } @@ -292,12 +292,12 @@ AllocatedBuffer will_engine::ResourceManager::createBuffer(const size_t allocSiz return newBuffer; } -AllocatedBuffer will_engine::ResourceManager::createHostSequentialBuffer(const size_t allocSize) const +AllocatedBuffer will_engine::ResourceManager::createHostSequentialBuffer(const size_t allocSize, const VkBufferUsageFlags additionalUsages) const { const VkBufferCreateInfo bufferInfo{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .size = allocSize, - .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | additionalUsages, .sharingMode = VK_SHARING_MODE_EXCLUSIVE }; @@ -425,7 +425,7 @@ VkDeviceAddress will_engine::ResourceManager::getBufferAddress(const AllocatedBu return srcPtr; } -void will_engine::ResourceManager::destroyBufferImmediate(AllocatedBuffer& buffer) const +void will_engine::ResourceManager::destroyImmediate(AllocatedBuffer& buffer) const { if (buffer.buffer == VK_NULL_HANDLE) { return; } vmaDestroyBuffer(context.allocator, buffer.buffer, buffer.allocation); @@ -433,7 +433,7 @@ void will_engine::ResourceManager::destroyBufferImmediate(AllocatedBuffer& buffe buffer.allocation = VK_NULL_HANDLE; } -void will_engine::ResourceManager::destroyBuffer(AllocatedBuffer& buffer) +void will_engine::ResourceManager::destroy(AllocatedBuffer& buffer) { if (buffer.buffer == VK_NULL_HANDLE) { return; } destructionQueues[lastKnownFrameOverlap].bufferQueue.push_back({buffer.buffer, buffer.allocation}); @@ -461,7 +461,7 @@ AllocatedImage will_engine::ResourceManager::createImage(const VkImageCreateInfo // allocate and create the image VK_CHECK(vmaCreateImage(context.allocator, &createInfo, &allocInfo, &newImage.image, &newImage.allocation, nullptr)); - const VkImageAspectFlags aspectFlag = createInfo.format == VK_FORMAT_D32_SFLOAT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + const VkImageAspectFlags aspectFlag = createInfo.format == VK_FORMAT_D32_SFLOAT || createInfo.format == VK_FORMAT_D32_SFLOAT_S8_UINT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; // build an image-view for the image VkImageViewCreateInfo view_info = vk_helpers::imageviewCreateInfo(createInfo.format, newImage.image, aspectFlag); @@ -473,7 +473,7 @@ AllocatedImage will_engine::ResourceManager::createImage(const VkImageCreateInfo } AllocatedImage will_engine::ResourceManager::createImage(const VkExtent3D size, const VkFormat format, const VkImageUsageFlags usage, - const bool mipmapped) const + const bool mipmapped, VkImageAspectFlagBits aspectFlag) const { AllocatedImage newImage{}; newImage.imageFormat = format; @@ -491,10 +491,13 @@ AllocatedImage will_engine::ResourceManager::createImage(const VkExtent3D size, // allocate and create the image VK_CHECK(vmaCreateImage(context.allocator, &imgInfo, &allocinfo, &newImage.image, &newImage.allocation, nullptr)); - const VkImageAspectFlags aspectFlag = format == VK_FORMAT_D32_SFLOAT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + VkImageAspectFlags targetAspect = aspectFlag; + if (targetAspect == VK_IMAGE_ASPECT_NONE) { + targetAspect = format == VK_FORMAT_D32_SFLOAT || format == VK_FORMAT_D32_SFLOAT_S8_UINT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + } // build a image-view for the image - VkImageViewCreateInfo view_info = vk_helpers::imageviewCreateInfo(format, newImage.image, aspectFlag); + VkImageViewCreateInfo view_info = vk_helpers::imageviewCreateInfo(format, newImage.image, targetAspect); view_info.subresourceRange.levelCount = imgInfo.mipLevels; VK_CHECK(vkCreateImageView(context.device, &view_info, nullptr, &newImage.imageView)); @@ -513,7 +516,7 @@ AllocatedImage will_engine::ResourceManager::createImage(const void* data, const const AllocatedImage newImage = createImage(size, format, usage | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, mipmapped); immediate.submit([&](VkCommandBuffer cmd) { - vk_helpers::transitionImage(cmd, newImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + vk_helpers::imageBarrier(cmd, newImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); VkBufferImageCopy copyRegion = {}; copyRegion.bufferOffset = 0; @@ -533,12 +536,12 @@ AllocatedImage will_engine::ResourceManager::createImage(const void* data, const vk_helpers::generateMipmaps(cmd, newImage.image, VkExtent2D{newImage.imageExtent.width, newImage.imageExtent.height}); } else { - vk_helpers::transitionImage(cmd, newImage.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + vk_helpers::imageBarrier(cmd, newImage.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); } }); - destroyBufferImmediate(uploadbuffer); + destroyImmediate(uploadbuffer); return newImage; } @@ -568,8 +571,9 @@ AllocatedImage will_engine::ResourceManager::createCubemap(const VkExtent3D size return newImage; } -void will_engine::ResourceManager::destroyImage(AllocatedImage& image) +void will_engine::ResourceManager::destroy(AllocatedImage& image) { + if (image.image == VK_NULL_HANDLE) { return; } destructionQueues[lastKnownFrameOverlap].imageQueue.push_back({image.image, image.allocation}); destructionQueues[lastKnownFrameOverlap].imageViewQueue.push_back(image.imageView); image.image = VK_NULL_HANDLE; @@ -579,7 +583,7 @@ void will_engine::ResourceManager::destroyImage(AllocatedImage& image) image.imageFormat = {}; } -void will_engine::ResourceManager::destroySampler(VkSampler sampler) +void will_engine::ResourceManager::destroy(VkSampler sampler) { destructionQueues[lastKnownFrameOverlap].samplerQueue.push_back(sampler); sampler = VK_NULL_HANDLE; @@ -609,9 +613,9 @@ int32_t will_engine::ResourceManager::setupDescriptorBufferUniform(DescriptorBuf return descriptorBuffer.setupData(context.device, uniformBuffers, index); } -void will_engine::ResourceManager::destroyDescriptorBuffer(DescriptorBuffer& descriptorBuffer) +void will_engine::ResourceManager::destroy(DescriptorBuffer& descriptorBuffer) { - destroyBuffer(descriptorBuffer.getBuffer()); + destroy(descriptorBuffer.getBuffer()); } VkShaderModule will_engine::ResourceManager::createShaderModule(const std::filesystem::path& path) const @@ -668,6 +672,12 @@ VkShaderModule will_engine::ResourceManager::createShaderModule(const std::files std::vector include_paths = {"shaders/include"}; options.SetIncluder(std::make_unique(include_paths)); + + // Macros + if (NORMAL_REMAP) { + options.AddMacroDefinition("REMAP_NORMALS"); + } + auto result = compiler.CompileGlslToSpv(source, kind, "shader", options); if (result.GetCompilationStatus() != shaderc_compilation_status_success) { @@ -694,7 +704,7 @@ VkShaderModule will_engine::ResourceManager::createShaderModule(const std::files return shaderModule; } -void will_engine::ResourceManager::destroyShaderModule(VkShaderModule& shaderModule) const +void will_engine::ResourceManager::destroy(VkShaderModule& shaderModule) const { vkDestroyShaderModule(context.device, shaderModule, nullptr); shaderModule = VK_NULL_HANDLE; @@ -707,7 +717,7 @@ VkPipelineLayout will_engine::ResourceManager::createPipelineLayout(const VkPipe return pipelineLayout; } -void will_engine::ResourceManager::destroyPipelineLayout(VkPipelineLayout pipelineLayout) +void will_engine::ResourceManager::destroy(VkPipelineLayout pipelineLayout) { if (pipelineLayout == VK_NULL_HANDLE) { return; } destructionQueues[lastKnownFrameOverlap].pipelineLayoutQueue.push_back(pipelineLayout); @@ -728,7 +738,7 @@ VkPipeline will_engine::ResourceManager::createComputePipeline(const VkComputePi return computePipeline; } -void will_engine::ResourceManager::destroyPipeline(VkPipeline pipeline) +void will_engine::ResourceManager::destroy(VkPipeline pipeline) { if (pipeline == VK_NULL_HANDLE) { return; } destructionQueues[lastKnownFrameOverlap].pipelineQueue.push_back(pipeline); @@ -742,7 +752,7 @@ VkDescriptorSetLayout will_engine::ResourceManager::createDescriptorSetLayout(De return layoutBuilder.build(context.device, shaderStageFlags, nullptr, layoutCreateFlags); } -void will_engine::ResourceManager::destroyDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout) +void will_engine::ResourceManager::destroy(VkDescriptorSetLayout descriptorSetLayout) { if (descriptorSetLayout == VK_NULL_HANDLE) { return; } destructionQueues[lastKnownFrameOverlap].descriptorSetLayoutQueue.push_back(descriptorSetLayout); @@ -756,7 +766,7 @@ VkImageView will_engine::ResourceManager::createImageView(const VkImageViewCreat return imageView; } -void will_engine::ResourceManager::destroyImageView(VkImageView imageView) +void will_engine::ResourceManager::destroy(VkImageView imageView) { if (imageView == VK_NULL_HANDLE) { return; } destructionQueues[lastKnownFrameOverlap].imageViewQueue.push_back(imageView); diff --git a/src/renderer/resource_manager.h b/src/renderer/resource_manager.h index d7941e75..6c4dc258 100644 --- a/src/renderer/resource_manager.h +++ b/src/renderer/resource_manager.h @@ -87,7 +87,7 @@ class ResourceManager public: // VkBuffer [[nodiscard]] AllocatedBuffer createBuffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage) const; - AllocatedBuffer createHostSequentialBuffer(size_t allocSize) const; + AllocatedBuffer createHostSequentialBuffer(size_t allocSize, VkBufferUsageFlags additionalUsages = 0) const; AllocatedBuffer createHostRandomBuffer(size_t allocSize, VkBufferUsageFlags additionalUsages = 0) const; @@ -102,9 +102,9 @@ class ResourceManager * \n should not be used otherwise, as the buffer may be destroyed before it is used. * @param buffer */ - void destroyBufferImmediate(AllocatedBuffer& buffer) const; + void destroyImmediate(AllocatedBuffer& buffer) const; - void destroyBuffer(AllocatedBuffer& buffer); + void destroy(AllocatedBuffer& buffer); public: // VkBuffer Helpers void copyBufferImmediate(const AllocatedBuffer& src, const AllocatedBuffer& dst, VkDeviceSize size) const; @@ -123,19 +123,19 @@ class ResourceManager public: // Samplers [[nodiscard]] VkSampler createSampler(const VkSamplerCreateInfo& createInfo) const; - void destroySampler(VkSampler sampler); + void destroy(VkSampler sampler); public: // VkImage and VkImageView [[nodiscard]] AllocatedImage createImage(const VkImageCreateInfo& createInfo) const; - [[nodiscard]] AllocatedImage createImage(VkExtent3D size, VkFormat format, VkImageUsageFlags usage, bool mipmapped = false) const; + [[nodiscard]] AllocatedImage createImage(VkExtent3D size, VkFormat format, VkImageUsageFlags usage, bool mipmapped = false, VkImageAspectFlagBits aspectFlag = VK_IMAGE_ASPECT_NONE) const; [[nodiscard]] AllocatedImage createImage(const void* data, size_t dataSize, VkExtent3D size, VkFormat format, VkImageUsageFlags usage, bool mipmapped = false) const; [[nodiscard]] AllocatedImage createCubemap(VkExtent3D size, VkFormat format, VkImageUsageFlags usage, bool mipmapped = false) const; - void destroyImage(AllocatedImage& image); + void destroy(AllocatedImage& image); public: // Descriptor Buffer [[nodiscard]] DescriptorBufferSampler createDescriptorBufferSampler(VkDescriptorSetLayout layout, int32_t maxObjectCount) const; @@ -148,7 +148,7 @@ class ResourceManager int32_t setupDescriptorBufferUniform(DescriptorBufferUniform& descriptorBuffer, const std::vector& uniformBuffers, int index = -1) const; - void destroyDescriptorBuffer(DescriptorBuffer& descriptorBuffer); + void destroy(DescriptorBuffer& descriptorBuffer); public: // Shader Module VkShaderModule createShaderModule(const std::filesystem::path& path) const; @@ -157,30 +157,30 @@ class ResourceManager * As far as I know shader modules don't need to defer destroyed, since it's used to construct the pipeline (without `ImmediateSubmitter`) * @param shaderModule */ - void destroyShaderModule(VkShaderModule& shaderModule) const; + void destroy(VkShaderModule& shaderModule) const; public: // Pipeline Layout VkPipelineLayout createPipelineLayout(const VkPipelineLayoutCreateInfo& createInfo) const; - void destroyPipelineLayout(VkPipelineLayout pipelineLayout); + void destroy(VkPipelineLayout pipelineLayout); public: // Pipelines VkPipeline createRenderPipeline(PipelineBuilder& builder, const std::vector& additionalDynamicStates = {}) const; VkPipeline createComputePipeline(const VkComputePipelineCreateInfo& pipelineInfo) const; - void destroyPipeline(VkPipeline pipeline); + void destroy(VkPipeline pipeline); public: // Descriptor Set Layout VkDescriptorSetLayout createDescriptorSetLayout(DescriptorLayoutBuilder& layoutBuilder, VkShaderStageFlagBits shaderStageFlags, VkDescriptorSetLayoutCreateFlagBits layoutCreateFlags) const; - void destroyDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout); + void destroy(VkDescriptorSetLayout descriptorSetLayout); public: // Image View VkImageView createImageView(const VkImageViewCreateInfo& viewInfo) const; - void destroyImageView(VkImageView imageView); + void destroy(VkImageView imageView); public: [[nodiscard]] VkSampler getDefaultSamplerLinear() const { return defaultSamplerLinear; } diff --git a/src/renderer/terrain/terrain_chunk.cpp b/src/renderer/terrain/terrain_chunk.cpp index 5bb05dd9..617dfbe5 100644 --- a/src/renderer/terrain/terrain_chunk.cpp +++ b/src/renderer/terrain/terrain_chunk.cpp @@ -40,7 +40,7 @@ TerrainChunk::TerrainChunk(ResourceManager& resourceManager, const std::vector& heightData) diff --git a/src/renderer/vk_helpers.cpp b/src/renderer/vk_helpers.cpp index 7574d63e..a2fff3ae 100644 --- a/src/renderer/vk_helpers.cpp +++ b/src/renderer/vk_helpers.cpp @@ -280,23 +280,23 @@ void will_engine::vk_helpers::copyBuffer(VkCommandBuffer cmd, const AllocatedBuf vkCmdCopyBuffer(cmd, src.buffer, dst.buffer, 1, &vertexCopy); } -void will_engine::vk_helpers::clearColorImage(VkCommandBuffer cmd, VkImageAspectFlagBits aspectFlag, VkImage image, VkImageLayout srcLayout, +void will_engine::vk_helpers::clearColorImage(VkCommandBuffer cmd, VkImageAspectFlags aspectFlag, VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, VkClearColorValue clearColor) { - transitionImage(cmd, image, srcLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); - constexpr VkImageSubresourceRange range{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + imageBarrier(cmd, image, srcLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, aspectFlag); + VkImageSubresourceRange range{ + .aspectMask = aspectFlag, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1 }; vkCmdClearColorImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range); - transitionImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dstLayout, VK_IMAGE_ASPECT_COLOR_BIT); + imageBarrier(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dstLayout, aspectFlag); } -void will_engine::vk_helpers::transitionImage(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout targetLayout, +void will_engine::vk_helpers::imageBarrier(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout targetLayout, VkImageAspectFlags aspectMask) { VkImageMemoryBarrier2 imageBarrier{.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; @@ -323,7 +323,7 @@ void will_engine::vk_helpers::transitionImage(VkCommandBuffer cmd, VkImage image vkCmdPipelineBarrier2(cmd, &depInfo); } -void will_engine::vk_helpers::synchronizeUniform(VkCommandBuffer cmd, const AllocatedBuffer& buffer, VkPipelineStageFlagBits2 srcPipelineStage, +void will_engine::vk_helpers::uniformBarrier(VkCommandBuffer cmd, const AllocatedBuffer& buffer, VkPipelineStageFlagBits2 srcPipelineStage, VkAccessFlagBits2 srcAccessBit, VkPipelineStageFlagBits2 dstPipelineStage, VkAccessFlagBits2 dstAccessBit) { @@ -387,40 +387,6 @@ void will_engine::vk_helpers::copyImageToImage(VkCommandBuffer cmd, VkImage sour vkCmdBlitImage2(cmd, &blitInfo); } -void will_engine::vk_helpers::copyDepthToDepth(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize) -{ - VkImageBlit2 blitRegion{.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, .pNext = nullptr}; - - blitRegion.srcOffsets[1].x = srcSize.width; - blitRegion.srcOffsets[1].y = srcSize.height; - blitRegion.srcOffsets[1].z = 1; - - blitRegion.dstOffsets[1].x = dstSize.width; - blitRegion.dstOffsets[1].y = dstSize.height; - blitRegion.dstOffsets[1].z = 1; - - blitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - blitRegion.srcSubresource.baseArrayLayer = 0; - blitRegion.srcSubresource.layerCount = 1; - blitRegion.srcSubresource.mipLevel = 0; - - blitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - blitRegion.dstSubresource.baseArrayLayer = 0; - blitRegion.dstSubresource.layerCount = 1; - blitRegion.dstSubresource.mipLevel = 0; - - VkBlitImageInfo2 blitInfo{.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, .pNext = nullptr}; - blitInfo.dstImage = destination; - blitInfo.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - blitInfo.srcImage = source; - blitInfo.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - blitInfo.filter = VK_FILTER_NEAREST; - blitInfo.regionCount = 1; - blitInfo.pRegions = &blitRegion; - - vkCmdBlitImage2(cmd, &blitInfo); -} - void will_engine::vk_helpers::generateMipmaps(VkCommandBuffer cmd, VkImage image, VkExtent2D imageSize) { const int mipLevels = static_cast(std::floor(std::log2(std::max(imageSize.width, imageSize.height)))) + 1; @@ -488,13 +454,13 @@ void will_engine::vk_helpers::generateMipmaps(VkCommandBuffer cmd, VkImage image } // transition all mip levels into the final read_only layout - transitionImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + imageBarrier(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); } void will_engine::vk_helpers::generateMipmapsCubemap(VkCommandBuffer cmd, VkImage image, VkExtent2D imageSize, VkImageLayout inputLayout, VkImageLayout ouputLayout) { - transitionImage(cmd, image, inputLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + imageBarrier(cmd, image, inputLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); const int mipLevels = static_cast(std::floor(std::log2(std::max(imageSize.width, imageSize.height)))) + 1; for (int mip = 0; mip < mipLevels; mip++) { @@ -561,7 +527,7 @@ void will_engine::vk_helpers::generateMipmapsCubemap(VkCommandBuffer cmd, VkImag } // transition all mip levels into the final read_only layout - transitionImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, ouputLayout, VK_IMAGE_ASPECT_COLOR_BIT); + imageBarrier(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, ouputLayout, VK_IMAGE_ASPECT_COLOR_BIT); } VkPipelineLayoutCreateInfo will_engine::vk_helpers::pipelineLayoutCreateInfo() @@ -594,195 +560,6 @@ VkPipelineShaderStageCreateInfo will_engine::vk_helpers::pipelineShaderStageCrea return info; } -void will_engine::vk_helpers::saveImageRGBA32F(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, - const AllocatedImage& image, const VkImageLayout imageLayout, - const VkImageAspectFlags aspectFlag, - const char* savePath, const bool overrideAlpha) -{ - constexpr int channelCount = 4; - const size_t dataSize = image.imageExtent.width * image.imageExtent.height * channelCount * sizeof(float); - AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - - immediate.submit([&](VkCommandBuffer cmd) { - VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = aspectFlag; - bufferCopyRegion.imageSubresource.mipLevel = 0; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = image.imageExtent; - bufferCopyRegion.bufferOffset = 0; - bufferCopyRegion.bufferRowLength = 0; - bufferCopyRegion.bufferImageHeight = 0; - - vk_helpers::transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); - - vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - vk_helpers::transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, VK_IMAGE_ASPECT_COLOR_BIT); - }); - - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); - - const auto byteImageData = new uint8_t[image.imageExtent.width * image.imageExtent.height * 4]; - const auto powEight = static_cast(pow(2, 8) - 1); - for (size_t i = 0; i < image.imageExtent.width * image.imageExtent.height; ++i) { - for (int j = 0; j < channelCount; j++) { - const auto value = static_cast(imageData[i * channelCount + j] * powEight); - byteImageData[i * 4 + j] = value; - } - - if (overrideAlpha) { - byteImageData[i * 4 + 3] = 255; - } - } - - stbi_write_png(savePath, image.imageExtent.width, image.imageExtent.height, 4, byteImageData, image.imageExtent.width * 4); - - delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); -} - -void will_engine::vk_helpers::saveImageRGBA16SFLOAT(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, - const AllocatedImage& image, VkImageLayout imageLayout, - VkImageAspectFlags aspectFlag, - const char* savePath, const bool overrideAlpha) -{ - using half_float::half; - constexpr int channelCount = 4; - const size_t dataSize = image.imageExtent.width * image.imageExtent.height * channelCount * sizeof(half); - AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - - immediate.submit([&](VkCommandBuffer cmd) { - VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = aspectFlag; - bufferCopyRegion.imageSubresource.mipLevel = 0; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = image.imageExtent; - bufferCopyRegion.bufferOffset = 0; - bufferCopyRegion.bufferRowLength = 0; - bufferCopyRegion.bufferImageHeight = 0; - - vk_helpers::transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); - - vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - vk_helpers::transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, VK_IMAGE_ASPECT_COLOR_BIT); - }); - - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); - - const auto byteImageData = new uint8_t[image.imageExtent.width * image.imageExtent.height * 4]; - for (size_t i = 0; i < image.imageExtent.width * image.imageExtent.height; ++i) { - for (int j = 0; j < channelCount; j++) { - auto value = static_cast(imageData[i * channelCount + j]); - value = std::max(0.0f, std::min(1.0f, value)); - byteImageData[i * 4 + j] = static_cast(std::lround(value * 255.0f)); - } - - if (overrideAlpha) { - byteImageData[i * 4 + 3] = 255; - } - } - - stbi_write_png(savePath, image.imageExtent.width, image.imageExtent.height, 4, byteImageData, image.imageExtent.width * 4); - - delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); -} - -void will_engine::vk_helpers::savePacked32Bit(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, - const AllocatedImage& image, VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, - const char* savePath, const std::function& unpackingFunction) -{ - const size_t dataSize = image.imageExtent.width * image.imageExtent.height * sizeof(uint32_t); - AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - - immediate.submit([&](VkCommandBuffer cmd) { - VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = aspectFlag; - bufferCopyRegion.imageSubresource.mipLevel = 0; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = image.imageExtent; - bufferCopyRegion.bufferOffset = 0; - bufferCopyRegion.bufferRowLength = 0; - bufferCopyRegion.bufferImageHeight = 0; - - vk_helpers::transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); - - vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - vk_helpers::transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, VK_IMAGE_ASPECT_COLOR_BIT); - }); - - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); - - const auto byteImageData = new uint8_t[image.imageExtent.width * image.imageExtent.height * 4]; - const auto powEight = powf(2, 8) - 1; - for (size_t i = 0; i < image.imageExtent.width * image.imageExtent.height; ++i) { - const glm::vec4 pixel = unpackingFunction(imageData[i]); - - byteImageData[i * 4] = static_cast(pixel.r * powEight); - byteImageData[i * 4 + 1] = static_cast(pixel.g * powEight); - byteImageData[i * 4 + 2] = static_cast(pixel.b * powEight); - byteImageData[i * 4 + 3] = static_cast(pixel.a * powEight); - } - - stbi_write_png(savePath, image.imageExtent.width, image.imageExtent.height, 4, byteImageData, image.imageExtent.width * 4); - - delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); -} - -void will_engine::vk_helpers::savePacked64Bit(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, - const AllocatedImage& image, VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, - const char* savePath, const std::function& unpackingFunction) -{ - const size_t dataSize = image.imageExtent.width * image.imageExtent.height * sizeof(uint64_t); - AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - - immediate.submit([&](VkCommandBuffer cmd) { - VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = aspectFlag; - bufferCopyRegion.imageSubresource.mipLevel = 0; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = image.imageExtent; - bufferCopyRegion.bufferOffset = 0; - bufferCopyRegion.bufferRowLength = 0; - bufferCopyRegion.bufferImageHeight = 0; - - vk_helpers::transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); - - vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - vk_helpers::transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, VK_IMAGE_ASPECT_COLOR_BIT); - }); - - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); - - const auto byteImageData = new uint8_t[image.imageExtent.width * image.imageExtent.height * 4]; - const auto powEight = powf(2, 8) - 1; - for (size_t i = 0; i < image.imageExtent.width * image.imageExtent.height; ++i) { - const glm::vec4 pixel = unpackingFunction(imageData[i]); - - byteImageData[i * 4] = static_cast(pixel.r * powEight); - byteImageData[i * 4 + 1] = static_cast(pixel.g * powEight); - byteImageData[i * 4 + 2] = static_cast(pixel.b * powEight); - byteImageData[i * 4 + 3] = static_cast(pixel.a * powEight); - } - - stbi_write_png(savePath, image.imageExtent.width, image.imageExtent.height, 4, byteImageData, image.imageExtent.width * 4); - - delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); -} - void will_engine::vk_helpers::saveImageR32F(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, const std::function& valueTransform, int32_t mipLevel) @@ -804,11 +581,11 @@ void will_engine::vk_helpers::saveImageR32F(const ResourceManager& resourceManag bufferCopyRegion.bufferRowLength = 0; bufferCopyRegion.bufferImageHeight = 0; - transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); + imageBarrier(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, aspectFlag); + imageBarrier(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, aspectFlag); }); void* data = receivingBuffer.info.pMappedData; @@ -828,192 +605,240 @@ void will_engine::vk_helpers::saveImageR32F(const ResourceManager& resourceManag stbi_write_png(savePath, static_cast(newXSize), static_cast(newYSize), 4, byteImageData, static_cast(newXSize) * 4); delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); + resourceManager.destroyImmediate(receivingBuffer); } -void will_engine::vk_helpers::saveImageR16F(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, - VkImageAspectFlags aspectFlag, const char* savePath, const std::function& valueTransform, - int32_t mipLevel) +void will_engine::vk_helpers::saveHeightmap(const std::vector& heightData, int width, int height, const std::filesystem::path& filename) { - size_t newXSize = image.imageExtent.width / static_cast(std::pow(2, mipLevel)); - size_t newYSize = image.imageExtent.height / static_cast(std::pow(2, mipLevel)); - const size_t texelCount = newXSize * newYSize; - const size_t dataSize = texelCount * 1 * sizeof(uint16_t); - AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - - immediate.submit([&, mipLevel](VkCommandBuffer cmd) { - VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = aspectFlag; - bufferCopyRegion.imageSubresource.mipLevel = mipLevel; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = {static_cast(newXSize), static_cast(newYSize), 1u}; - bufferCopyRegion.bufferOffset = 0; - bufferCopyRegion.bufferRowLength = 0; - bufferCopyRegion.bufferImageHeight = 0; - - transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectFlag); - - vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, aspectFlag); - }); + float minHeight = std::numeric_limits::max(); + float maxHeight = std::numeric_limits::lowest(); - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); + for (const float _height : heightData) { + minHeight = std::min(minHeight, _height); + maxHeight = std::max(maxHeight, _height); + } + const auto byteImageData = new uint8_t[width * height]; - const auto byteImageData = new uint8_t[texelCount * 4]; - const auto powEight = static_cast(pow(2, 8) - 1); - for (size_t i = 0; i < texelCount; ++i) { - const uint16_t rvalue = imageData[i]; - const float floatValue = valueTransform(rvalue); - const auto value = static_cast(floatValue * powEight); - byteImageData[i * 4 + 0] = value; - byteImageData[i * 4 + 1] = value; - byteImageData[i * 4 + 2] = value; - byteImageData[i * 4 + 3] = 255; + for (size_t i = 0; i < width * height; ++i) { + float normalizedHeight = (heightData[i] - minHeight) / (maxHeight - minHeight); + normalizedHeight = std::max(0.0f, std::min(1.0f, normalizedHeight)); + byteImageData[i] = static_cast(std::lround(normalizedHeight * 255.0f)); } - stbi_write_png(savePath, static_cast(newXSize), static_cast(newYSize), 4, byteImageData, static_cast(newXSize) * 4); + stbi_write_png(filename.string().c_str(), width, height, 1, byteImageData, width); delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); } -void will_engine::vk_helpers::saveImageR8UNORM(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, - const AllocatedImage& image, VkImageLayout imageLayout, const char* savePath, int32_t mipLevel) -{ - const size_t width = image.imageExtent.width / static_cast(std::pow(2, mipLevel)); - const size_t height = image.imageExtent.height / static_cast(std::pow(2, mipLevel)); - const size_t texelCount = width * height; - const size_t dataSize = texelCount * 1 * sizeof(uint8_t); - - AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - - immediate.submit([&, mipLevel](VkCommandBuffer cmd) { - VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - bufferCopyRegion.imageSubresource.mipLevel = mipLevel; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = {static_cast(width), static_cast(height), 1u}; - bufferCopyRegion.bufferOffset = 0; - bufferCopyRegion.bufferRowLength = 0; - bufferCopyRegion.bufferImageHeight = 0; - - transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); - - vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, VK_IMAGE_ASPECT_COLOR_BIT); - }); - - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); - - const auto byteImageData = new uint8_t[texelCount * 4]; - for (size_t i = 0; i < texelCount; ++i) { - const auto value = imageData[i]; - byteImageData[i * 4 + 0] = value; - byteImageData[i * 4 + 1] = value; - byteImageData[i * 4 + 2] = value; - byteImageData[i * 4 + 3] = 255; +will_engine::vk_helpers::FormatInfo will_engine::vk_helpers::getFormatInfo(ImageFormat format, bool stencilOnly) +{ + switch (format) { + case ImageFormat::RGBA32F: + return {16, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::RGBA16F: + return {sizeof(half_float::half) * 4, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::RGBA8: + return {4, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::RGBA8_UNORM: + return {sizeof(uint8_t) * 4, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::R32F: + return {4, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::R16F: + return {2, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::R8UNORM: + return {1, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::R8UINT: + return {1, VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::A2R10G10B10_UNORM: + return {sizeof(uint32_t), VK_IMAGE_ASPECT_COLOR_BIT}; + case ImageFormat::D32S8: + return {stencilOnly ? sizeof(uint8_t) : sizeof(uint32_t), VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT}; + default: + return {0, 0}; } - - stbi_write_png(savePath, static_cast(width), static_cast(height), 4, byteImageData, static_cast(width) * 4); - - delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); } -void will_engine::vk_helpers::saveImageR8G8B8A8UNORM(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, - const AllocatedImage& image, VkImageLayout imageLayout, const char* savePath, int32_t mipLevel) +void will_engine::vk_helpers::saveImage(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, + const AllocatedImage& image, VkImageLayout imageLayout, + ImageFormat format, const std::string& savePath, bool saveStencilOnly) { - const size_t width = image.imageExtent.width / static_cast(std::pow(2, mipLevel)); - const size_t height = image.imageExtent.height / static_cast(std::pow(2, mipLevel)); - const size_t texelCount = width * height; - const size_t dataSize = texelCount * 4 * sizeof(uint8_t); + const FormatInfo info = getFormatInfo(format, saveStencilOnly); + const VkImageAspectFlags aspectMask = info.aspectMask; + VkImageAspectFlags subresourceAspect = aspectMask; + // This will look different if `VK_KHR_separate_depth_stencil_layouts` is enabled + if (info.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + subresourceAspect = saveStencilOnly ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + } + const uint32_t texelCount = image.imageExtent.width * image.imageExtent.height; + const size_t dataSize = texelCount * info.bytesPerPixel; AllocatedBuffer receivingBuffer = resourceManager.createReceivingBuffer(dataSize); - immediate.submit([&, mipLevel](VkCommandBuffer cmd) { + immediate.submit([&](VkCommandBuffer cmd) { VkBufferImageCopy bufferCopyRegion{}; - bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - bufferCopyRegion.imageSubresource.mipLevel = mipLevel; + bufferCopyRegion.imageSubresource.aspectMask = subresourceAspect; + bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.baseArrayLayer = 0; bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent = {static_cast(width), static_cast(height), 1u}; + bufferCopyRegion.imageExtent = image.imageExtent; bufferCopyRegion.bufferOffset = 0; bufferCopyRegion.bufferRowLength = 0; bufferCopyRegion.bufferImageHeight = 0; - transitionImage(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_ASPECT_COLOR_BIT); - + imageBarrier(cmd, image.image, imageLayout, VK_IMAGE_LAYOUT_GENERAL, aspectMask); vkCmdCopyImageToBuffer(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, receivingBuffer.buffer, 1, &bufferCopyRegion); - - transitionImage(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, VK_IMAGE_ASPECT_COLOR_BIT); + imageBarrier(cmd, image.image, VK_IMAGE_LAYOUT_GENERAL, imageLayout, aspectMask); }); - void* data = receivingBuffer.info.pMappedData; - const auto imageData = static_cast(data); - const auto byteImageData = new uint8_t[texelCount * 4]; - for (size_t i = 0; i < texelCount; ++i) { - const auto value = imageData[i]; - byteImageData[i * 4 + 0] = imageData[i * 4 + 0]; - byteImageData[i * 4 + 1] = imageData[i * 4 + 1]; - byteImageData[i * 4 + 2] = imageData[i * 4 + 2]; - // overwrite alpha to 1.0f - byteImageData[i * 4 + 3] = 255; - } + void* data = receivingBuffer.info.pMappedData; + std::vector outputData(texelCount * 4); + processImageData(data, outputData, texelCount, format, saveStencilOnly); - stbi_write_png(savePath, static_cast(width), static_cast(height), 4, byteImageData, static_cast(width) * 4); + stbi_write_png(savePath.c_str(), image.imageExtent.width, image.imageExtent.height, 4, outputData.data(), image.imageExtent.width * 4); - delete[] byteImageData; - resourceManager.destroyBufferImmediate(receivingBuffer); + resourceManager.destroyImmediate(receivingBuffer); } -void will_engine::vk_helpers::saveImage(const std::vector& imageData, int width, int height, std::filesystem::path filename, - bool overrideAlpha) +void will_engine::vk_helpers::processImageData(void* sourceData, std::span targetData, uint32_t pixelCount, ImageFormat format, + bool stencilOnly) { - const auto byteImageData = new uint8_t[width * height * 4]; - for (size_t i = 0; i < width * height; ++i) { - for (int j = 0; j < 4; j++) { - auto value = static_cast(imageData[i * 4 + j]); - value = std::max(0.0f, std::min(1.0f, value)); - byteImageData[i * 4 + j] = static_cast(std::lround(value * 255.0f)); - } + constexpr float powEight = 255.0f; - if (overrideAlpha) { - byteImageData[i * 4 + 3] = 255; + switch (format) { + case ImageFormat::RGBA32F: + { + const auto floatData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + for (uint32_t c = 0; c < 4; ++c) { + const float value = std::max(0.0f, std::min(1.0f, floatData[i * 4 + c])); + targetData[i * 4 + c] = static_cast(value * powEight); + } + } + break; } - } - stbi_write_png(filename.string().c_str(), width, height, 4, byteImageData, width * 4); - delete[] byteImageData; -} + case ImageFormat::RGBA16F: + { + const auto halfData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + for (uint32_t c = 0; c < 4; ++c) { + float value = halfData[i * 4 + c]; + value = std::max(0.0f, std::min(1.0f, value)); + targetData[i * 4 + c] = static_cast(value * powEight); + } + } + break; + } -void will_engine::vk_helpers::saveHeightmap(const std::vector& heightData, int width, int height, const std::filesystem::path& filename) -{ - float minHeight = std::numeric_limits::max(); - float maxHeight = std::numeric_limits::lowest(); + case ImageFormat::RGBA8: + { + const auto packedData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const uint32_t pixel = packedData[i]; + targetData[i * 4] = (pixel & 0xFF); + targetData[i * 4 + 1] = ((pixel >> 8) & 0xFF); + targetData[i * 4 + 2] = ((pixel >> 16) & 0xFF); + targetData[i * 4 + 3] = ((pixel >> 24) & 0xFF); + } + break; + } + case ImageFormat::RGBA8_UNORM: + { + const auto packedData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const glm::vec4 pixel = glm::unpackUnorm4x8(packedData[i]); + targetData[i * 4] = pixel.r * powEight; + targetData[i * 4 + 1] = pixel.g * powEight; + targetData[i * 4 + 2] = pixel.b * powEight; + targetData[i * 4 + 3] = powEight; + } + break; + } - for (const float _height : heightData) { - minHeight = std::min(minHeight, _height); - maxHeight = std::max(maxHeight, _height); - } + case ImageFormat::R32F: + { + const auto floatData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const float depth = floatData[i]; + for (uint32_t c = 0; c < 3; ++c) { + targetData[i * 4 + c] = static_cast(depth * powEight); + } + targetData[i * 4 + 3] = powEight; + } + break; + } - const auto byteImageData = new uint8_t[width * height]; + case ImageFormat::R16F: + { + const auto halfData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const float depth = halfData[i]; + for (uint32_t c = 0; c < 3; ++c) { + targetData[i * 4 + c] = static_cast(depth * powEight); + } + targetData[i * 4 + 3] = 255; + } + break; + } - for (size_t i = 0; i < width * height; ++i) { - float normalizedHeight = (heightData[i] - minHeight) / (maxHeight - minHeight); - normalizedHeight = std::max(0.0f, std::min(1.0f, normalizedHeight)); - byteImageData[i] = static_cast(std::lround(normalizedHeight * 255.0f)); + case ImageFormat::R8UNORM: + case ImageFormat::R8UINT: + { + const uint8_t* byteSource = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const uint8_t value = byteSource[i]; + for (uint32_t c = 0; c < 3; ++c) { + targetData[i * 4 + c] = value; + } + targetData[i * 4 + 3] = 255; + } + break; + } + case ImageFormat::A2R10G10B10_UNORM: + { + const uint32_t* byteSource = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const uint32_t value = byteSource[i]; + + // Extract components according to A2R10G10B10 layout (AI BS) + const float r = static_cast((value >> 20) & 0x3FF) / 1023.0f; + const float g = static_cast((value >> 10) & 0x3FF) / 1023.0f; + const float b = static_cast(value & 0x3FF) / 1023.0f; + //const float a = static_cast((value >> 30) & 0x3) / 3.0f; + + targetData[i * 4 + 0] = static_cast(r * powEight); + targetData[i * 4 + 1] = static_cast(g * powEight); + targetData[i * 4 + 2] = static_cast(b * powEight); + //targetData[i * 4 + 3] = static_cast(a * 255.0f); + targetData[i * 4 + 3] = powEight; + } + break; + } + case ImageFormat::D32S8: + { + if (stencilOnly) { + const uint8_t* byteSource = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const uint8_t stencil = byteSource[i]; + for (uint32_t c = 0; c < 3; ++c) { + targetData[i * 4 + c] = stencil * 255.0f; + } + targetData[i * 4 + 3] = 255; + } + } + else { + const auto depthData = static_cast(sourceData); + for (uint32_t i = 0; i < pixelCount; ++i) { + const float depth = depthData[i]; + for (uint32_t c = 0; c < 3; ++c) { + targetData[i * 4 + c] = static_cast(depth * powEight); + } + targetData[i * 4 + 3] = 255; + } + } + break; + } } - - stbi_write_png(filename.string().c_str(), width, height, 1, byteImageData, width); - - delete[] byteImageData; } diff --git a/src/renderer/vk_helpers.h b/src/renderer/vk_helpers.h index 853fee11..d3351344 100644 --- a/src/renderer/vk_helpers.h +++ b/src/renderer/vk_helpers.h @@ -6,6 +6,7 @@ #define VKHELPERS_H #include #include +#include #include #include @@ -26,6 +27,28 @@ class ImmediateSubmitter; namespace vk_helpers { + // Enum to define supported image formats + enum class ImageFormat + { + RGBA32F, + RGBA16F, + RGBA8, + RGBA8_UNORM, + A2R10G10B10_UNORM, + R32F, + R16F, + R8UNORM, + R8UINT, + D32S8 + }; + + // Structure to hold format-specific parameters + struct FormatInfo + { + uint64_t bytesPerPixel; + VkImageAspectFlags aspectMask; + }; + VkImageCreateInfo imageCreateInfo(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent); VkImageCreateInfo cubemapCreateInfo(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent); @@ -80,23 +103,20 @@ namespace vk_helpers */ VkDeviceSize getAlignedSize(VkDeviceSize value, VkDeviceSize alignment); - void copyBuffer(VkCommandBuffer cmd, const AllocatedBuffer& src, VkDeviceSize srcOffset, const AllocatedBuffer& dst, VkDeviceSize dstOffset, VkDeviceSize size); + void copyBuffer(VkCommandBuffer cmd, const AllocatedBuffer& src, VkDeviceSize srcOffset, const AllocatedBuffer& dst, VkDeviceSize dstOffset, + VkDeviceSize size); - void clearColorImage(VkCommandBuffer cmd, VkImageAspectFlagBits aspectFlag, VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, + void clearColorImage(VkCommandBuffer cmd, VkImageAspectFlags aspectFlag, VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, VkClearColorValue clearColor = {0.0f, 0.0f, 0.0f, 1.0f}); - void transitionImage(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout targetLayout, VkImageAspectFlags aspectMask); - - void transitionImage(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageAspectFlags aspectMask, VkImageLayout targetLayout); + void imageBarrier(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout targetLayout, VkImageAspectFlags aspectMask); - void synchronizeUniform(VkCommandBuffer cmd, const AllocatedBuffer& buffer, VkPipelineStageFlagBits2 srcPipelineStage, + void uniformBarrier(VkCommandBuffer cmd, const AllocatedBuffer& buffer, VkPipelineStageFlagBits2 srcPipelineStage, VkAccessFlagBits2 srcAccessBit, VkPipelineStageFlagBits2 dstPipelineStage, VkAccessFlagBits2 dstAccessBit); void copyImageToImage(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize); - void copyDepthToDepth(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize); - void generateMipmaps(VkCommandBuffer cmd, VkImage image, VkExtent2D imageSize); void generateMipmapsCubemap(VkCommandBuffer cmd, VkImage image, VkExtent2D imageSize, VkImageLayout inputLayout, VkImageLayout ouputLayout); @@ -107,20 +127,6 @@ namespace vk_helpers VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule shaderModule, const char* entry = "main"); - void saveImageRGBA32F(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, bool overrideAlpha = true); - - void saveImageRGBA16SFLOAT(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, bool overrideAlpha = true); - - void savePacked32Bit(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, - const std::function& unpackingFunction); - - void savePacked64Bit(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, - const std::function& unpackingFunction); - /** * Save the Allocated image as a grayscaled image. The image must be a format with only 1 channel (e.g. R32 or D32) */ @@ -128,19 +134,21 @@ namespace vk_helpers VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, const std::function& valueTransform, int32_t mipLevel = 0); - void saveImageR16F(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, VkImageAspectFlags aspectFlag, const char* savePath, - const std::function& valueTransform, int32_t mipLevel = 0); - - void saveImageR8UNORM(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, const char* savePath, int32_t mipLevel = 0); + void saveHeightmap(const std::vector& heightData, int width, int height, const std::filesystem::path& filename); - void saveImageR8G8B8A8UNORM(const ResourceManager& resourceManager, const ImmediateSubmitter& immediate, const AllocatedImage& image, - VkImageLayout imageLayout, const char* savePath, int32_t mipLevel = 0); + FormatInfo getFormatInfo(ImageFormat format, bool stencilOnly); - void saveImage(const std::vector& imageData, int width, int height, std::filesystem::path filename, bool overrideAlpha = true); + void processImageData(void* sourceData, std::span targetData, + uint32_t pixelCount, + ImageFormat format, bool stencilOnly = false); - void saveHeightmap(const std::vector& heightData, int width, int height, const std::filesystem::path& filename); + void saveImage(const ResourceManager& resourceManager, + const ImmediateSubmitter& immediate, + const AllocatedImage& image, + VkImageLayout imageLayout, + ImageFormat format, + const std::string& savePath, + bool saveStencilOnly = false); } } diff --git a/src/renderer/vk_pipelines.cpp b/src/renderer/vk_pipelines.cpp index 3c655e87..aa4bb09e 100644 --- a/src/renderer/vk_pipelines.cpp +++ b/src/renderer/vk_pipelines.cpp @@ -170,12 +170,12 @@ void will_engine::PipelineBuilder::setupInputAssembly(const VkPrimitiveTopology inputAssembly.primitiveRestartEnable = enablePrimitiveRestart; } -void will_engine::PipelineBuilder::setupRasterization(const VkPolygonMode polygonMode, const VkCullModeFlags cullMode, const VkFrontFace frontFace, - bool rasterizerDiscardEnable) +void will_engine::PipelineBuilder::setupRasterization(VkPolygonMode polygonMode, VkCullModeFlags cullMode, VkFrontFace frontFace, + float lineWidth, bool rasterizerDiscardEnable) { // Draw Mode rasterizer.polygonMode = polygonMode; - rasterizer.lineWidth = 1.0f; + rasterizer.lineWidth = lineWidth; // Culling rasterizer.cullMode = cullMode; @@ -205,11 +205,11 @@ void will_engine::PipelineBuilder::setupMultisampling(VkBool32 sampleShadingEnab multisampling.alphaToOneEnable = alphaToOneEnable; } -void will_engine::PipelineBuilder::setupRenderer(const std::vector& colorattachmentFormat, const VkFormat depthAttachmentFormat) +void will_engine::PipelineBuilder::setupRenderer(const std::vector& colorAttachmentFormat, const VkFormat depthAttachmentFormat, const VkFormat stencilAttachmentFormat) { // Color Format - if (!colorattachmentFormat.empty()) { - colorAttachmentFormats = colorattachmentFormat; + if (!colorAttachmentFormat.empty()) { + colorAttachmentFormats = colorAttachmentFormat; renderInfo.colorAttachmentCount = colorAttachmentFormats.size(); renderInfo.pColorAttachmentFormats = colorAttachmentFormats.data(); } @@ -218,6 +218,11 @@ void will_engine::PipelineBuilder::setupRenderer(const std::vector& co if (depthAttachmentFormat != VK_FORMAT_UNDEFINED) { renderInfo.depthAttachmentFormat = depthAttachmentFormat; } + + // Stencil Format + if (stencilAttachmentFormat != VK_FORMAT_UNDEFINED) { + renderInfo.stencilAttachmentFormat = stencilAttachmentFormat; + } } void will_engine::PipelineBuilder::setupDepthStencil(VkBool32 depthTestEnable, VkBool32 depthWriteEnable, VkCompareOp compareOp, VkBool32 depthBoundsTestEnable, diff --git a/src/renderer/vk_pipelines.h b/src/renderer/vk_pipelines.h index 8ad9d587..029007fc 100644 --- a/src/renderer/vk_pipelines.h +++ b/src/renderer/vk_pipelines.h @@ -46,7 +46,7 @@ class PipelineBuilder void setupInputAssembly(VkPrimitiveTopology topology, bool enablePrimitiveRestart = false); - void setupRasterization(VkPolygonMode polygonMode, VkCullModeFlags cullMode, VkFrontFace frontFace, bool rasterizerDiscardEnable = false); + void setupRasterization(VkPolygonMode polygonMode, VkCullModeFlags cullMode, VkFrontFace frontFace, float lineWidth = 1.0f, bool rasterizerDiscardEnable = false); /** * Use to initialize the depth bias of the pipeline. @@ -60,7 +60,7 @@ class PipelineBuilder void setupMultisampling(VkBool32 sampleShadingEnable, VkSampleCountFlagBits rasterizationSamples, float minSampleShading, const VkSampleMask* pSampleMask, VkBool32 alphaToCoverageEnable, VkBool32 alphaToOneEnable); - void setupRenderer(const std::vector& colorattachmentFormat, VkFormat depthAttachmentFormat); + void setupRenderer(const std::vector& colorAttachmentFormat, VkFormat depthAttachmentFormat = VK_FORMAT_UNDEFINED, VkFormat stencilAttachmentFormat = VK_FORMAT_UNDEFINED); /** * Set up the depth and stencil for this pipeline @@ -101,10 +101,12 @@ class PipelineBuilder */ void disableDepthTest(); - VkPipelineDynamicStateCreateInfo generateDynamicStates(VkDynamicState states[], uint32_t count); void setupTessellation(int32_t controlPoints = 4); +private: + VkPipelineDynamicStateCreateInfo generateDynamicStates(VkDynamicState states[], uint32_t count); + private: std::vector shaderStages; diff --git a/src/renderer/vulkan_context.cpp b/src/renderer/vulkan_context.cpp index 4227edef..a0c2544f 100644 --- a/src/renderer/vulkan_context.cpp +++ b/src/renderer/vulkan_context.cpp @@ -52,6 +52,7 @@ VulkanContext::VulkanContext(SDL_Window* window, bool useValidationLayers) otherFeatures.tessellationShader = VK_TRUE; otherFeatures.fillModeNonSolid = VK_TRUE; otherFeatures.independentBlend = VK_TRUE; + otherFeatures.wideLines = VK_TRUE; // Descriptor Buffer Extension VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufferFeatures = {};