From 88002c337c40d19072b9004af298e9de71d01abc Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 30 Jun 2025 17:04:04 +0700 Subject: [PATCH 01/18] initial skeleton for debug draw ex --- 34_DebugDraw/CMakeLists.txt | 39 ++ .../app_resources/simple.fragment.hlsl | 11 + 34_DebugDraw/app_resources/simple.vertex.hlsl | 21 ++ 34_DebugDraw/app_resources/simple_common.hlsl | 20 + 34_DebugDraw/config.json.template | 28 ++ 34_DebugDraw/include/CDrawAABB.h | 5 + 34_DebugDraw/include/common.hpp | 26 ++ 34_DebugDraw/include/transform.hpp | 154 ++++++++ 34_DebugDraw/main.cpp | 348 ++++++++++++++++++ 34_DebugDraw/pipeline.groovy | 50 +++ 34_DebugDraw/src/CDrawAABB.cpp | 5 + 34_DebugDraw/src/transform.cpp | 0 CMakeLists.txt | 2 + 13 files changed, 709 insertions(+) create mode 100644 34_DebugDraw/CMakeLists.txt create mode 100644 34_DebugDraw/app_resources/simple.fragment.hlsl create mode 100644 34_DebugDraw/app_resources/simple.vertex.hlsl create mode 100644 34_DebugDraw/app_resources/simple_common.hlsl create mode 100644 34_DebugDraw/config.json.template create mode 100644 34_DebugDraw/include/CDrawAABB.h create mode 100644 34_DebugDraw/include/common.hpp create mode 100644 34_DebugDraw/include/transform.hpp create mode 100644 34_DebugDraw/main.cpp create mode 100644 34_DebugDraw/pipeline.groovy create mode 100644 34_DebugDraw/src/CDrawAABB.cpp create mode 100644 34_DebugDraw/src/transform.cpp diff --git a/34_DebugDraw/CMakeLists.txt b/34_DebugDraw/CMakeLists.txt new file mode 100644 index 000000000..4031b45c6 --- /dev/null +++ b/34_DebugDraw/CMakeLists.txt @@ -0,0 +1,39 @@ +if(NBL_BUILD_IMGUI) + set(NBL_EXTRA_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/src/transform.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/CDrawAABB.cpp" # TODO remove when moved to nabla + ) + + set(NBL_INCLUDE_SERACH_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}/include" + ) + + # TODO remove + list(APPEND NBL_LIBRARIES + imtestengine + imguizmo + "${NBL_EXT_IMGUI_UI_LIB}" + ) + + nbl_create_executable_project("${NBL_EXTRA_SOURCES}" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") + LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} geometryCreatorSpirvBRD) # TODO probably can remove + + # TODO probably remove when moved to nabla + if(NBL_EMBED_BUILTIN_RESOURCES) + set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData) + set(RESOURCE_DIR "app_resources") + + get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE) + + file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*") + foreach(RES_FILE ${BUILTIN_RESOURCE_FILES}) + LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}") + endforeach() + + ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}") + + LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_}) + endif() +endif() \ No newline at end of file diff --git a/34_DebugDraw/app_resources/simple.fragment.hlsl b/34_DebugDraw/app_resources/simple.fragment.hlsl new file mode 100644 index 000000000..ccd8bdffd --- /dev/null +++ b/34_DebugDraw/app_resources/simple.fragment.hlsl @@ -0,0 +1,11 @@ +#pragma shader_stage(fragment) + +#include "simple_common.hlsl" + +[shader("pixel")] +float32_t4 main(PSInput input) : SV_TARGET +{ + float32_t4 outColor = input.color; + + return outColor; +} \ No newline at end of file diff --git a/34_DebugDraw/app_resources/simple.vertex.hlsl b/34_DebugDraw/app_resources/simple.vertex.hlsl new file mode 100644 index 000000000..3dfb8d621 --- /dev/null +++ b/34_DebugDraw/app_resources/simple.vertex.hlsl @@ -0,0 +1,21 @@ +#pragma shader_stage(vertex) + +#include "nbl/builtin/hlsl/bda/__ptr.hlsl" +#include "simple_common.hlsl" + +using namespace nbl::hlsl; + +[[vk::push_constant]] SPushConstants pc; + +[shader("vertex")] +PSInput main(uint vertexID : SV_VertexID) +{ + PSInput output; + + float32_t4 vertex = (bda::__ptr::create(pc.pVertices) + vertexID).deref_restrict().load(); + + output.position = vertex; + output.color = float32_t4(1, 0, 0, 1); + + return output; +} \ No newline at end of file diff --git a/34_DebugDraw/app_resources/simple_common.hlsl b/34_DebugDraw/app_resources/simple_common.hlsl new file mode 100644 index 000000000..6567165fb --- /dev/null +++ b/34_DebugDraw/app_resources/simple_common.hlsl @@ -0,0 +1,20 @@ +#ifndef _DRAW_AABB_SIMPLE_COMMON_HLSL +#define _DRAW_AABB_SIMPLE_COMMON_HLSL + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" + +struct SPushConstants +{ + // mat4 transform + uint64_t pVertices; +}; + +#ifdef __HLSL_VERSION +struct PSInput +{ + float32_t4 position : SV_Position; + float32_t4 color : TEXCOORD0; +}; +#endif + +#endif diff --git a/34_DebugDraw/config.json.template b/34_DebugDraw/config.json.template new file mode 100644 index 000000000..f961745c1 --- /dev/null +++ b/34_DebugDraw/config.json.template @@ -0,0 +1,28 @@ +{ + "enableParallelBuild": true, + "threadsPerBuildProcess" : 2, + "isExecuted": false, + "scriptPath": "", + "cmake": { + "configurations": [ "Release", "Debug", "RelWithDebInfo" ], + "buildModes": [], + "requiredOptions": [] + }, + "profiles": [ + { + "backend": "vulkan", + "platform": "windows", + "buildModes": [], + "runConfiguration": "Release", + "gpuArchitectures": [] + } + ], + "dependencies": [], + "data": [ + { + "dependencies": [], + "command": [""], + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h new file mode 100644 index 000000000..65a8142a1 --- /dev/null +++ b/34_DebugDraw/include/CDrawAABB.h @@ -0,0 +1,5 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +// TODO move this into nabla \ No newline at end of file diff --git a/34_DebugDraw/include/common.hpp b/34_DebugDraw/include/common.hpp new file mode 100644 index 000000000..014f9643e --- /dev/null +++ b/34_DebugDraw/include/common.hpp @@ -0,0 +1,26 @@ +#ifndef __NBL_THIS_EXAMPLE_COMMON_H_INCLUDED__ +#define __NBL_THIS_EXAMPLE_COMMON_H_INCLUDED__ + +#include + +// common api +#include "CCamera.hpp" +#include "SimpleWindowedApplication.hpp" +#include "CEventCallback.hpp" + +// the example's headers +#include "transform.hpp" +#include "CGeomtryCreatorScene.hpp" +#include "CDrawAABB.h" + +using namespace nbl; +using namespace core; +using namespace hlsl; +using namespace system; +using namespace asset; +using namespace ui; +using namespace video; +using namespace scene; +using namespace geometrycreator; + +#endif // __NBL_THIS_EXAMPLE_COMMON_H_INCLUDED__ \ No newline at end of file diff --git a/34_DebugDraw/include/transform.hpp b/34_DebugDraw/include/transform.hpp new file mode 100644 index 000000000..88a78f751 --- /dev/null +++ b/34_DebugDraw/include/transform.hpp @@ -0,0 +1,154 @@ +#ifndef __NBL_THIS_EXAMPLE_TRANSFORM_H_INCLUDED__ +#define __NBL_THIS_EXAMPLE_TRANSFORM_H_INCLUDED__ + +#include "nbl/ui/ICursorControl.h" +#include "nbl/ext/ImGui/ImGui.h" +#include "imgui/imgui_internal.h" +#include "imguizmo/ImGuizmo.h" + +static constexpr inline auto OfflineSceneTextureIx = 1u; + +struct TransformRequestParams +{ + bool useWindow = true, editTransformDecomposition = false, enableViewManipulate = false; + float camDistance = 8.f; +}; + +void EditTransform(float* cameraView, const float* cameraProjection, float* matrix, const TransformRequestParams& params) +{ + static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE); + static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL); + static bool useSnap = false; + static float snap[3] = { 1.f, 1.f, 1.f }; + static float bounds[] = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; + static float boundsSnap[] = { 0.1f, 0.1f, 0.1f }; + static bool boundSizing = false; + static bool boundSizingSnap = false; + + if (params.editTransformDecomposition) + { + if (ImGui::IsKeyPressed(ImGuiKey_T)) + mCurrentGizmoOperation = ImGuizmo::TRANSLATE; + if (ImGui::IsKeyPressed(ImGuiKey_R)) + mCurrentGizmoOperation = ImGuizmo::ROTATE; + if (ImGui::IsKeyPressed(ImGuiKey_S)) + mCurrentGizmoOperation = ImGuizmo::SCALE; + if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE)) + mCurrentGizmoOperation = ImGuizmo::TRANSLATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE)) + mCurrentGizmoOperation = ImGuizmo::ROTATE; + ImGui::SameLine(); + if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE)) + mCurrentGizmoOperation = ImGuizmo::SCALE; + if (ImGui::RadioButton("Universal", mCurrentGizmoOperation == ImGuizmo::UNIVERSAL)) + mCurrentGizmoOperation = ImGuizmo::UNIVERSAL; + float matrixTranslation[3], matrixRotation[3], matrixScale[3]; + ImGuizmo::DecomposeMatrixToComponents(matrix, matrixTranslation, matrixRotation, matrixScale); + ImGui::InputFloat3("Tr", matrixTranslation); + ImGui::InputFloat3("Rt", matrixRotation); + ImGui::InputFloat3("Sc", matrixScale); + ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix); + + if (mCurrentGizmoOperation != ImGuizmo::SCALE) + { + if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL)) + mCurrentGizmoMode = ImGuizmo::LOCAL; + ImGui::SameLine(); + if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD)) + mCurrentGizmoMode = ImGuizmo::WORLD; + } + if (ImGui::IsKeyPressed(ImGuiKey_S) && ImGui::IsKeyPressed(ImGuiKey_LeftShift)) + useSnap = !useSnap; + ImGui::Checkbox("##UseSnap", &useSnap); + ImGui::SameLine(); + + switch (mCurrentGizmoOperation) + { + case ImGuizmo::TRANSLATE: + ImGui::InputFloat3("Snap", &snap[0]); + break; + case ImGuizmo::ROTATE: + ImGui::InputFloat("Angle Snap", &snap[0]); + break; + case ImGuizmo::SCALE: + ImGui::InputFloat("Scale Snap", &snap[0]); + break; + } + ImGui::Checkbox("Bound Sizing", &boundSizing); + if (boundSizing) + { + ImGui::PushID(3); + ImGui::Checkbox("##BoundSizing", &boundSizingSnap); + ImGui::SameLine(); + ImGui::InputFloat3("Snap", boundsSnap); + ImGui::PopID(); + } + } + + ImGuiIO& io = ImGui::GetIO(); + float viewManipulateRight = io.DisplaySize.x; + float viewManipulateTop = 0; + static ImGuiWindowFlags gizmoWindowFlags = 0; + + /* + for the "useWindow" case we just render to a gui area, + otherwise to fake full screen transparent window + + note that for both cases we make sure gizmo being + rendered is aligned to our texture scene using + imgui "cursor" screen positions + */ + + SImResourceInfo info; + info.textureID = OfflineSceneTextureIx; + info.samplerIx = (uint16_t)nbl::ext::imgui::UI::DefaultSamplerIx::USER; + + if (params.useWindow) + { + ImGui::SetNextWindowSize(ImVec2(800, 400), ImGuiCond_Appearing); + ImGui::SetNextWindowPos(ImVec2(400, 20), ImGuiCond_Appearing); + ImGui::PushStyleColor(ImGuiCol_WindowBg, (ImVec4)ImColor(0.35f, 0.3f, 0.3f)); + ImGui::Begin("Gizmo", 0, gizmoWindowFlags); + ImGuizmo::SetDrawlist(); + + ImVec2 contentRegionSize = ImGui::GetContentRegionAvail(); + ImVec2 windowPos = ImGui::GetWindowPos(); + ImVec2 cursorPos = ImGui::GetCursorScreenPos(); + + ImGui::Image(info, contentRegionSize); + ImGuizmo::SetRect(cursorPos.x, cursorPos.y, contentRegionSize.x, contentRegionSize.y); + + viewManipulateRight = cursorPos.x + contentRegionSize.x; + viewManipulateTop = cursorPos.y; + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + gizmoWindowFlags = (ImGui::IsWindowHovered() && ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max) ? ImGuiWindowFlags_NoMove : 0); + } + else + { + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(io.DisplaySize); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); // fully transparent fake window + ImGui::Begin("FullScreenWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs); + + ImVec2 contentRegionSize = ImGui::GetContentRegionAvail(); + ImVec2 cursorPos = ImGui::GetCursorScreenPos(); + + ImGui::Image(info, contentRegionSize); + ImGuizmo::SetRect(cursorPos.x, cursorPos.y, contentRegionSize.x, contentRegionSize.y); + + viewManipulateRight = cursorPos.x + contentRegionSize.x; + viewManipulateTop = cursorPos.y; + } + + ImGuizmo::Manipulate(cameraView, cameraProjection, mCurrentGizmoOperation, mCurrentGizmoMode, matrix, NULL, useSnap ? &snap[0] : NULL, boundSizing ? bounds : NULL, boundSizingSnap ? boundsSnap : NULL); + + if(params.enableViewManipulate) + ImGuizmo::ViewManipulate(cameraView, params.camDistance, ImVec2(viewManipulateRight - 128, viewManipulateTop), ImVec2(128, 128), 0x10101010); + + ImGui::End(); + ImGui::PopStyleColor(); +} + +#endif // __NBL_THIS_EXAMPLE_TRANSFORM_H_INCLUDED__ \ No newline at end of file diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp new file mode 100644 index 000000000..53d028891 --- /dev/null +++ b/34_DebugDraw/main.cpp @@ -0,0 +1,348 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +#include "common.hpp" +#include "app_resources/simple_common.hlsl" + +class DebugDrawSampleApp final : public examples::SimpleWindowedApplication +{ + using device_base_t = examples::SimpleWindowedApplication; + + _NBL_STATIC_INLINE_CONSTEXPR uint32_t WIN_W = 1280, WIN_H = 720; + +public: + inline DebugDrawSampleApp(const path& _localInputCWD, const path& _localOutputCWD, const path& _sharedInputCWD, const path& _sharedOutputCWD) + : IApplicationFramework(_localInputCWD, _localOutputCWD, _sharedInputCWD, _sharedOutputCWD) {} + + inline core::vector getSurfaces() const override + { + if (!m_surface) + { + { + auto windowCallback = core::make_smart_refctd_ptr(smart_refctd_ptr(m_inputSystem), smart_refctd_ptr(m_logger)); + IWindow::SCreationParams params = {}; + params.callback = core::make_smart_refctd_ptr(); + params.width = WIN_W; + params.height = WIN_H; + params.x = 32; + params.y = 32; + params.flags = ui::IWindow::ECF_HIDDEN | IWindow::ECF_BORDERLESS | IWindow::ECF_RESIZABLE; + params.windowCaption = "DebugDrawSampleApp"; + params.callback = windowCallback; + const_cast&>(m_window) = m_winMgr->createWindow(std::move(params)); + } + + auto surface = CSurfaceVulkanWin32::create(smart_refctd_ptr(m_api), smart_refctd_ptr_static_cast(m_window)); + const_cast&>(m_surface) = nbl::video::CSimpleResizeSurface::create(std::move(surface)); + } + + if (m_surface) + return { {m_surface->getSurface()/*,EQF_NONE*/} }; + + return {}; + } + + inline bool onAppInitialized(smart_refctd_ptr&& system) override + { + m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); + + if (!device_base_t::onAppInitialized(smart_refctd_ptr(system))) + return false; + + m_assetManager = make_smart_refctd_ptr(smart_refctd_ptr(m_system)); + auto* geometry = m_assetManager->getGeometryCreator(); + + m_semaphore = m_device->createSemaphore(m_realFrameIx); + if (!m_semaphore) + return logFail("Failed to Create a Semaphore!"); + + ISwapchain::SCreationParams swapchainParams = { .surface = m_surface->getSurface() }; + if (!swapchainParams.deduceFormat(m_physicalDevice)) + return logFail("Could not choose a Surface Format for the Swapchain!"); + + const static IGPURenderpass::SCreationParams::SSubpassDependency dependencies[] = + { + { + .srcSubpass = IGPURenderpass::SCreationParams::SSubpassDependency::External, + .dstSubpass = 0, + .memoryBarrier = + { + .srcStageMask = asset::PIPELINE_STAGE_FLAGS::COPY_BIT, + .srcAccessMask = asset::ACCESS_FLAGS::TRANSFER_WRITE_BIT, + .dstStageMask = asset::PIPELINE_STAGE_FLAGS::COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = asset::ACCESS_FLAGS::COLOR_ATTACHMENT_WRITE_BIT + } + }, + { + .srcSubpass = 0, + .dstSubpass = IGPURenderpass::SCreationParams::SSubpassDependency::External, + .memoryBarrier = + { + .srcStageMask = asset::PIPELINE_STAGE_FLAGS::COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = asset::ACCESS_FLAGS::COLOR_ATTACHMENT_WRITE_BIT + } + }, + IGPURenderpass::SCreationParams::DependenciesEnd + }; + + auto scResources = std::make_unique(m_device.get(), swapchainParams.surfaceFormat.format, dependencies); + auto* renderpass = scResources->getRenderpass(); + + if (!renderpass) + return logFail("Failed to create Renderpass!"); + + auto gQueue = getGraphicsQueue(); + if (!m_surface || !m_surface->init(gQueue, std::move(scResources), swapchainParams.sharedParams)) + return logFail("Could not create Window & Surface or initialize the Surface!"); + + m_cmdPool = m_device->createCommandPool(gQueue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); + + for (auto i = 0u; i < MaxFramesInFlight; i++) + { + if (!m_cmdPool) + return logFail("Couldn't create Command Pool!"); + if (!m_cmdPool->createCommandBuffers(IGPUCommandPool::BUFFER_LEVEL::PRIMARY, { m_cmdBufs.data() + i, 1 })) + return logFail("Couldn't create Command Buffer!"); + } + + m_winMgr->setWindowSize(m_window.get(), WIN_W, WIN_H); + m_surface->recreateSwapchain(); + + { + IGPUBuffer::SCreationParams params; + params.size = sizeof(float32_t4) * vertices.size(); + params.usage = IGPUBuffer::EUF_STORAGE_BUFFER_BIT | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; + + m_utils->createFilledDeviceLocalBufferOnDedMem( + SIntendedSubmitInfo{ .queue = getTransferUpQueue() }, + std::move(params), + vertices.data() + ).move_into(verticesBuffer); + } + + auto compileShader = [&](const std::string& filePath) -> smart_refctd_ptr + { + IAssetLoader::SAssetLoadParams lparams = {}; + lparams.logger = m_logger.get(); + lparams.workingDirectory = localInputCWD; + auto bundle = m_assetManager->getAsset(filePath, lparams); + if (bundle.getContents().empty() || bundle.getAssetType() != IAsset::ET_SHADER) + { + m_logger->log("Shader %s not found!", ILogger::ELL_ERROR, filePath.c_str()); + exit(-1); + } + + const auto assets = bundle.getContents(); + assert(assets.size() == 1); + smart_refctd_ptr shaderSrc = IAsset::castDown(assets[0]); + if (!shaderSrc) + return nullptr; + + return m_device->compileShader({ shaderSrc.get() }); + }; + auto vertexShader = compileShader("app_resources/simple.vertex.hlsl"); + auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); + + const asset::SPushConstantRange pcRange = { .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, .offset = 0, .size = sizeof(SPushConstants) }; + const auto pipelineLayout = m_device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); + + IGPUGraphicsPipeline::SCreationParams params[1] = {}; + params[0].layout = pipelineLayout.get(); + params[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main", }; + params[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main", }; + params[0].cached = { + .primitiveAssembly = { + .primitiveType = E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, + } + }; + params[0].renderpass = renderpass; + + if (!m_device->createGraphicsPipelines(nullptr, params, &m_pipeline)) + return logFail("Graphics pipeline creation failed"); + + m_window->setCaption("[Nabla Engine] Debug Draw App Test Demo"); + m_winMgr->show(m_window.get()); + oracle.reportBeginFrameRecord(); + camera.mapKeysToArrows(); + + return true; + } + + inline void workLoopBody() override + { + // framesInFlight: ensuring safe execution of command buffers and acquires, `framesInFlight` only affect semaphore waits, don't use this to index your resources because it can change with swapchain recreation. + const uint32_t framesInFlight = core::min(MaxFramesInFlight, m_surface->getMaxAcquiresInFlight()); + // We block for semaphores for 2 reasons here: + // A) Resource: Can't use resource like a command buffer BEFORE previous use is finished! [MaxFramesInFlight] + // B) Acquire: Can't have more acquires in flight than a certain threshold returned by swapchain or your surface helper class. [MaxAcquiresInFlight] + if (m_realFrameIx >= framesInFlight) + { + const ISemaphore::SWaitInfo cbDonePending[] = + { + { + .semaphore = m_semaphore.get(), + .value = m_realFrameIx + 1 - framesInFlight + } + }; + if (m_device->blockForSemaphores(cbDonePending) != ISemaphore::WAIT_RESULT::SUCCESS) + return; + } + + const auto resourceIx = m_realFrameIx % MaxFramesInFlight; + + // render whole scene to offline frame buffer & submit + + auto* const cmdbuf = m_cmdBufs.data()[resourceIx].get(); + cmdbuf->reset(IGPUCommandBuffer::RESET_FLAGS::RELEASE_RESOURCES_BIT); + cmdbuf->begin(IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT); + cmdbuf->beginDebugMarker("DebugDrawSampleApp IMGUI Frame"); + + auto* queue = getGraphicsQueue(); + + asset::SViewport viewport; + { + viewport.minDepth = 1.f; + viewport.maxDepth = 0.f; + viewport.x = 0u; + viewport.y = 0u; + viewport.width = WIN_W; + viewport.height = WIN_H; + } + cmdbuf->setViewport(0u, 1u, &viewport); + + const VkRect2D currentRenderArea = + { + .offset = {0,0}, + .extent = {m_window->getWidth(),m_window->getHeight()} + }; + + { + auto scRes = static_cast(m_surface->getSwapchainResources()); + const IGPUCommandBuffer::SClearColorValue clearValue = { .float32 = {0.f,0.f,0.f,1.f} }; + const IGPUCommandBuffer::SRenderpassBeginInfo beginInfo = + { + .framebuffer = scRes->getFramebuffer(m_currentImageAcquire.imageIndex), + .colorClearValues = &clearValue, + .depthStencilClearValues = nullptr, + .renderArea = currentRenderArea + }; + + SPushConstants pc; + pc.pVertices = verticesBuffer->getDeviceAddress(); + + cmdbuf->beginRenderPass(beginInfo, IGPUCommandBuffer::SUBPASS_CONTENTS::INLINE); + cmdbuf->bindGraphicsPipeline(m_pipeline.get()); + cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); + cmdbuf->draw(vertices.size(), 1, 0, 0); + + cmdbuf->endRenderPass(); + } + cmdbuf->end(); + + { + const IQueue::SSubmitInfo::SSemaphoreInfo rendered[] = + { + { + .semaphore = m_semaphore.get(), + .value = ++m_realFrameIx, + .stageMask = PIPELINE_STAGE_FLAGS::COLOR_ATTACHMENT_OUTPUT_BIT + } + }; + + { + { + const IQueue::SSubmitInfo::SCommandBufferInfo commandBuffers[] = + { + {.cmdbuf = cmdbuf } + }; + + const IQueue::SSubmitInfo::SSemaphoreInfo acquired[] = + { + { + .semaphore = m_currentImageAcquire.semaphore, + .value = m_currentImageAcquire.acquireCount, + .stageMask = PIPELINE_STAGE_FLAGS::NONE + } + }; + + const IQueue::SSubmitInfo infos[] = + { + { + .waitSemaphores = acquired, + .commandBuffers = commandBuffers, + .signalSemaphores = rendered + } + }; + + if (queue->submit(infos) == IQueue::RESULT::SUCCESS) + { + const nbl::video::ISemaphore::SWaitInfo waitInfos[] = + { { + .semaphore = m_semaphore.get(), + .value = m_realFrameIx + } }; + + m_device->blockForSemaphores(waitInfos); // this is not solution, quick wa to not throw validation errors + } + else + --m_realFrameIx; + } + } + + m_surface->present(m_currentImageAcquire.imageIndex, rendered); + } + } + + inline bool keepRunning() override + { + if (m_surface->irrecoverable()) + return false; + + return true; + } + + inline bool onAppTerminated() override + { + return device_base_t::onAppTerminated(); + } + +private: + // Maximum frames which can be simultaneously submitted, used to cycle through our per-frame resources like command buffers + constexpr static inline uint32_t MaxFramesInFlight = 3u; + + smart_refctd_ptr m_window; + smart_refctd_ptr> m_surface; + smart_refctd_ptr m_pipeline; + smart_refctd_ptr m_semaphore; + smart_refctd_ptr m_cmdPool; + uint64_t m_realFrameIx = 0; + std::array, MaxFramesInFlight> m_cmdBufs; + ISimpleManagedSurface::SAcquireResult m_currentImageAcquire = {}; + + smart_refctd_ptr m_assetManager; + core::smart_refctd_ptr m_inputSystem; + InputSystem::ChannelReader mouse; + InputSystem::ChannelReader keyboard; + + core::smart_refctd_ptr m_descriptorSetPool; + + Camera camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); + video::CDumbPresentationOracle oracle; + + uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed + + TransformRequestParams transformParams; + bool isPerspective = true, isLH = true, flipGizmoY = true, move = false; + float fov = 60.f, zNear = 0.1f, zFar = 10000.f, moveSpeed = 1.f, rotateSpeed = 1.f; + float viewWidth = 10.f; + float camYAngle = 165.f / 180.f * 3.14159f; + float camXAngle = 32.f / 180.f * 3.14159f; + + bool firstFrame = true; + + std::array vertices = { float32_t4(0,0,0,0), float32_t4(0,1,0,0) }; + smart_refctd_ptr verticesBuffer; +}; + +NBL_MAIN_FUNC(DebugDrawSampleApp) \ No newline at end of file diff --git a/34_DebugDraw/pipeline.groovy b/34_DebugDraw/pipeline.groovy new file mode 100644 index 000000000..4c0efec03 --- /dev/null +++ b/34_DebugDraw/pipeline.groovy @@ -0,0 +1,50 @@ +import org.DevshGraphicsProgramming.Agent +import org.DevshGraphicsProgramming.BuilderInfo +import org.DevshGraphicsProgramming.IBuilder + +class CDebugDrawBuilder extends IBuilder +{ + public CDebugDrawBuilder(Agent _agent, _info) + { + super(_agent, _info) + } + + @Override + public boolean prepare(Map axisMapping) + { + return true + } + + @Override + public boolean build(Map axisMapping) + { + IBuilder.CONFIGURATION config = axisMapping.get("CONFIGURATION") + IBuilder.BUILD_TYPE buildType = axisMapping.get("BUILD_TYPE") + + def nameOfBuildDirectory = getNameOfBuildDirectory(buildType) + def nameOfConfig = getNameOfConfig(config) + + agent.execute("cmake --build ${info.rootProjectPath}/${nameOfBuildDirectory}/${info.targetProjectPathRelativeToRoot} --target ${info.targetBaseName} --config ${nameOfConfig} -j12 -v") + + return true + } + + @Override + public boolean test(Map axisMapping) + { + return true + } + + @Override + public boolean install(Map axisMapping) + { + return true + } +} + +def create(Agent _agent, _info) +{ + return new CDebugDrawBuilder(_agent, _info) +} + +return this \ No newline at end of file diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp new file mode 100644 index 000000000..65a8142a1 --- /dev/null +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -0,0 +1,5 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +// TODO move this into nabla \ No newline at end of file diff --git a/34_DebugDraw/src/transform.cpp b/34_DebugDraw/src/transform.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/CMakeLists.txt b/CMakeLists.txt index 31ebaddf9..88f208241 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,8 @@ if(NBL_BUILD_EXAMPLES) # Showcase compute pathtracing add_subdirectory(30_ComputeShaderPathTracer EXCLUDE_FROM_ALL) + add_subdirectory(34_DebugDraw EXCLUDE_FROM_ALL) + add_subdirectory(38_EXRSplit EXCLUDE_FROM_ALL) # if (NBL_BUILD_MITSUBA_LOADER AND NBL_BUILD_OPTIX) # add_subdirectory(39_DenoiserTonemapper EXCLUDE_FROM_ALL) From 3df145b22a01b100fb536745e8e731b2ce84cb73 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 1 Jul 2025 10:49:35 +0700 Subject: [PATCH 02/18] use camera with lines --- 34_DebugDraw/app_resources/simple.vertex.hlsl | 2 +- 34_DebugDraw/app_resources/simple_common.hlsl | 6 +- 34_DebugDraw/main.cpp | 58 ++++++++++++++++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/34_DebugDraw/app_resources/simple.vertex.hlsl b/34_DebugDraw/app_resources/simple.vertex.hlsl index 3dfb8d621..9651154bd 100644 --- a/34_DebugDraw/app_resources/simple.vertex.hlsl +++ b/34_DebugDraw/app_resources/simple.vertex.hlsl @@ -14,7 +14,7 @@ PSInput main(uint vertexID : SV_VertexID) float32_t4 vertex = (bda::__ptr::create(pc.pVertices) + vertexID).deref_restrict().load(); - output.position = vertex; + output.position = mul(pc.MVP, vertex); output.color = float32_t4(1, 0, 0, 1); return output; diff --git a/34_DebugDraw/app_resources/simple_common.hlsl b/34_DebugDraw/app_resources/simple_common.hlsl index 6567165fb..5fc0d0b63 100644 --- a/34_DebugDraw/app_resources/simple_common.hlsl +++ b/34_DebugDraw/app_resources/simple_common.hlsl @@ -5,7 +5,11 @@ struct SPushConstants { - // mat4 transform +#ifdef __HLSL_VERSION + float32_t4x4 MVP; +#else + float MVP[4*4]; +#endif uint64_t pVertices; }; diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 53d028891..d339c7505 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -53,6 +53,13 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication m_assetManager = make_smart_refctd_ptr(smart_refctd_ptr(m_system)); auto* geometry = m_assetManager->getGeometryCreator(); + { + core::vectorSIMDf cameraPosition(14, 8, 12); + core::vectorSIMDf cameraTarget(0, 0, 0); + matrix4SIMD projectionMatrix = matrix4SIMD::buildProjectionMatrixPerspectiveFovLH(core::radians(60.0f), float(WIN_W) / WIN_H, zNear, zFar); + camera = Camera(cameraPosition, cameraTarget, projectionMatrix, moveSpeed, rotateSpeed); + } + m_semaphore = m_device->createSemaphore(m_realFrameIx); if (!m_semaphore) return logFail("Failed to Create a Semaphore!"); @@ -164,7 +171,6 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication m_window->setCaption("[Nabla Engine] Debug Draw App Test Demo"); m_winMgr->show(m_window.get()); oracle.reportBeginFrameRecord(); - camera.mapKeysToArrows(); return true; } @@ -191,6 +197,25 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication const auto resourceIx = m_realFrameIx % MaxFramesInFlight; + m_inputSystem->getDefaultMouse(&mouse); + m_inputSystem->getDefaultKeyboard(&keyboard); + + auto updatePresentationTimestamp = [&]() + { + m_currentImageAcquire = m_surface->acquireNextImage(); + + oracle.reportEndFrameRecord(); + const auto timestamp = oracle.getNextPresentationTimeStamp(); + oracle.reportBeginFrameRecord(); + + return timestamp; + }; + + const auto nextPresentationTimestamp = updatePresentationTimestamp(); + + if (!m_currentImageAcquire) + return; + // render whole scene to offline frame buffer & submit auto* const cmdbuf = m_cmdBufs.data()[resourceIx].get(); @@ -198,6 +223,25 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication cmdbuf->begin(IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT); cmdbuf->beginDebugMarker("DebugDrawSampleApp IMGUI Frame"); + { + camera.beginInputProcessing(nextPresentationTimestamp); + mouse.consumeEvents([&](const IMouseEventChannel::range_t& events) -> void { camera.mouseProcess(events); }, m_logger.get()); + keyboard.consumeEvents([&](const IKeyboardEventChannel::range_t& events) -> void { camera.keyboardProcess(events); }, m_logger.get()); + camera.endInputProcessing(nextPresentationTimestamp); + } + + core::matrix4SIMD modelViewProjectionMatrix; + { + const auto viewMatrix = camera.getViewMatrix(); + const auto projectionMatrix = camera.getProjectionMatrix(); + const auto viewProjectionMatrix = camera.getConcatenatedMatrix(); + + core::matrix3x4SIMD modelMatrix; + modelMatrix.setTranslation(nbl::core::vectorSIMDf(0, 0, 0, 0)); + modelMatrix.setRotation(quaternion(0, 0, 0)); + modelViewProjectionMatrix = core::concatenateBFollowedByA(viewProjectionMatrix, modelMatrix); + } + auto* queue = getGraphicsQueue(); asset::SViewport viewport; @@ -211,6 +255,12 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication } cmdbuf->setViewport(0u, 1u, &viewport); + VkRect2D scissor{ + .offset = { 0, 0 }, + .extent = { m_window->getWidth(), m_window->getHeight() } + }; + cmdbuf->setScissor(0u, 1u, &scissor); + const VkRect2D currentRenderArea = { .offset = {0,0}, @@ -229,11 +279,13 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication }; SPushConstants pc; + memcpy(pc.MVP, modelViewProjectionMatrix.pointer(), sizeof(pc.MVP)); pc.pVertices = verticesBuffer->getDeviceAddress(); cmdbuf->beginRenderPass(beginInfo, IGPUCommandBuffer::SUBPASS_CONTENTS::INLINE); cmdbuf->bindGraphicsPipeline(m_pipeline.get()); cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); + cmdbuf->setLineWidth(1.f); cmdbuf->draw(vertices.size(), 1, 0, 0); cmdbuf->endRenderPass(); @@ -327,7 +379,7 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication core::smart_refctd_ptr m_descriptorSetPool; - Camera camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); + Camera camera; video::CDumbPresentationOracle oracle; uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed @@ -341,7 +393,7 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication bool firstFrame = true; - std::array vertices = { float32_t4(0,0,0,0), float32_t4(0,1,0,0) }; + std::array vertices = { float32_t4(0,0,0,1), float32_t4(10,10,-10,1) }; smart_refctd_ptr verticesBuffer; }; From 6d5a495f757066941976a57985aca46c088cb626 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 1 Jul 2025 11:27:20 +0700 Subject: [PATCH 03/18] fixes from mesh_loader merge --- 34_DebugDraw/CMakeLists.txt | 1 - 34_DebugDraw/include/common.hpp | 14 +++++--------- 34_DebugDraw/main.cpp | 20 +++++++++----------- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/34_DebugDraw/CMakeLists.txt b/34_DebugDraw/CMakeLists.txt index 4031b45c6..12f418600 100644 --- a/34_DebugDraw/CMakeLists.txt +++ b/34_DebugDraw/CMakeLists.txt @@ -16,7 +16,6 @@ if(NBL_BUILD_IMGUI) ) nbl_create_executable_project("${NBL_EXTRA_SOURCES}" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") - LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} geometryCreatorSpirvBRD) # TODO probably can remove # TODO probably remove when moved to nabla if(NBL_EMBED_BUILTIN_RESOURCES) diff --git a/34_DebugDraw/include/common.hpp b/34_DebugDraw/include/common.hpp index 014f9643e..599c9a2e9 100644 --- a/34_DebugDraw/include/common.hpp +++ b/34_DebugDraw/include/common.hpp @@ -3,14 +3,11 @@ #include -// common api -#include "CCamera.hpp" -#include "SimpleWindowedApplication.hpp" -#include "CEventCallback.hpp" +#include "nbl/examples/cameras/CCamera.hpp" +#include "nbl/examples/common/SimpleWindowedApplication.hpp" +#include "nbl/examples/common/CEventCallback.hpp" +#include "nbl/examples/examples.hpp" -// the example's headers -#include "transform.hpp" -#include "CGeomtryCreatorScene.hpp" #include "CDrawAABB.h" using namespace nbl; @@ -20,7 +17,6 @@ using namespace system; using namespace asset; using namespace ui; using namespace video; -using namespace scene; -using namespace geometrycreator; +using namespace nbl::examples; #endif // __NBL_THIS_EXAMPLE_COMMON_H_INCLUDED__ \ No newline at end of file diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index d339c7505..3c29b258b 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -5,9 +5,10 @@ #include "common.hpp" #include "app_resources/simple_common.hlsl" -class DebugDrawSampleApp final : public examples::SimpleWindowedApplication +class DebugDrawSampleApp final : public SimpleWindowedApplication, public BuiltinResourcesApplication { - using device_base_t = examples::SimpleWindowedApplication; + using device_base_t = SimpleWindowedApplication; + using asset_base_t = BuiltinResourcesApplication; _NBL_STATIC_INLINE_CONSTEXPR uint32_t WIN_W = 1280, WIN_H = 720; @@ -20,7 +21,7 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication if (!m_surface) { { - auto windowCallback = core::make_smart_refctd_ptr(smart_refctd_ptr(m_inputSystem), smart_refctd_ptr(m_logger)); + auto windowCallback = core::make_smart_refctd_ptr(smart_refctd_ptr(m_inputSystem), smart_refctd_ptr(m_logger)); IWindow::SCreationParams params = {}; params.callback = core::make_smart_refctd_ptr(); params.width = WIN_W; @@ -49,9 +50,8 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication if (!device_base_t::onAppInitialized(smart_refctd_ptr(system))) return false; - - m_assetManager = make_smart_refctd_ptr(smart_refctd_ptr(m_system)); - auto* geometry = m_assetManager->getGeometryCreator(); + if (!asset_base_t::onAppInitialized(smart_refctd_ptr(system))) + return false; { core::vectorSIMDf cameraPosition(14, 8, 12); @@ -133,7 +133,7 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication IAssetLoader::SAssetLoadParams lparams = {}; lparams.logger = m_logger.get(); lparams.workingDirectory = localInputCWD; - auto bundle = m_assetManager->getAsset(filePath, lparams); + auto bundle = m_assetMgr->getAsset(filePath, lparams); if (bundle.getContents().empty() || bundle.getAssetType() != IAsset::ET_SHADER) { m_logger->log("Shader %s not found!", ILogger::ELL_ERROR, filePath.c_str()); @@ -372,10 +372,9 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication std::array, MaxFramesInFlight> m_cmdBufs; ISimpleManagedSurface::SAcquireResult m_currentImageAcquire = {}; - smart_refctd_ptr m_assetManager; core::smart_refctd_ptr m_inputSystem; - InputSystem::ChannelReader mouse; - InputSystem::ChannelReader keyboard; + InputSystem::ChannelReader mouse; + InputSystem::ChannelReader keyboard; core::smart_refctd_ptr m_descriptorSetPool; @@ -384,7 +383,6 @@ class DebugDrawSampleApp final : public examples::SimpleWindowedApplication uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed - TransformRequestParams transformParams; bool isPerspective = true, isLH = true, flipGizmoY = true, move = false; float fov = 60.f, zNear = 0.1f, zFar = 10000.f, moveSpeed = 1.f, rotateSpeed = 1.f; float viewWidth = 10.f; From c5dae9857a22ecb9388f4d2cb757ffe2140e2b47 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 1 Jul 2025 11:38:43 +0700 Subject: [PATCH 04/18] removed unused files --- 34_DebugDraw/CMakeLists.txt | 1 - 34_DebugDraw/include/transform.hpp | 154 ----------------------------- 34_DebugDraw/src/transform.cpp | 0 3 files changed, 155 deletions(-) delete mode 100644 34_DebugDraw/include/transform.hpp delete mode 100644 34_DebugDraw/src/transform.cpp diff --git a/34_DebugDraw/CMakeLists.txt b/34_DebugDraw/CMakeLists.txt index 12f418600..60c07b1b7 100644 --- a/34_DebugDraw/CMakeLists.txt +++ b/34_DebugDraw/CMakeLists.txt @@ -1,6 +1,5 @@ if(NBL_BUILD_IMGUI) set(NBL_EXTRA_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/src/transform.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/CDrawAABB.cpp" # TODO remove when moved to nabla ) diff --git a/34_DebugDraw/include/transform.hpp b/34_DebugDraw/include/transform.hpp deleted file mode 100644 index 88a78f751..000000000 --- a/34_DebugDraw/include/transform.hpp +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef __NBL_THIS_EXAMPLE_TRANSFORM_H_INCLUDED__ -#define __NBL_THIS_EXAMPLE_TRANSFORM_H_INCLUDED__ - -#include "nbl/ui/ICursorControl.h" -#include "nbl/ext/ImGui/ImGui.h" -#include "imgui/imgui_internal.h" -#include "imguizmo/ImGuizmo.h" - -static constexpr inline auto OfflineSceneTextureIx = 1u; - -struct TransformRequestParams -{ - bool useWindow = true, editTransformDecomposition = false, enableViewManipulate = false; - float camDistance = 8.f; -}; - -void EditTransform(float* cameraView, const float* cameraProjection, float* matrix, const TransformRequestParams& params) -{ - static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE); - static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL); - static bool useSnap = false; - static float snap[3] = { 1.f, 1.f, 1.f }; - static float bounds[] = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f }; - static float boundsSnap[] = { 0.1f, 0.1f, 0.1f }; - static bool boundSizing = false; - static bool boundSizingSnap = false; - - if (params.editTransformDecomposition) - { - if (ImGui::IsKeyPressed(ImGuiKey_T)) - mCurrentGizmoOperation = ImGuizmo::TRANSLATE; - if (ImGui::IsKeyPressed(ImGuiKey_R)) - mCurrentGizmoOperation = ImGuizmo::ROTATE; - if (ImGui::IsKeyPressed(ImGuiKey_S)) - mCurrentGizmoOperation = ImGuizmo::SCALE; - if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE)) - mCurrentGizmoOperation = ImGuizmo::TRANSLATE; - ImGui::SameLine(); - if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE)) - mCurrentGizmoOperation = ImGuizmo::ROTATE; - ImGui::SameLine(); - if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE)) - mCurrentGizmoOperation = ImGuizmo::SCALE; - if (ImGui::RadioButton("Universal", mCurrentGizmoOperation == ImGuizmo::UNIVERSAL)) - mCurrentGizmoOperation = ImGuizmo::UNIVERSAL; - float matrixTranslation[3], matrixRotation[3], matrixScale[3]; - ImGuizmo::DecomposeMatrixToComponents(matrix, matrixTranslation, matrixRotation, matrixScale); - ImGui::InputFloat3("Tr", matrixTranslation); - ImGui::InputFloat3("Rt", matrixRotation); - ImGui::InputFloat3("Sc", matrixScale); - ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix); - - if (mCurrentGizmoOperation != ImGuizmo::SCALE) - { - if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL)) - mCurrentGizmoMode = ImGuizmo::LOCAL; - ImGui::SameLine(); - if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD)) - mCurrentGizmoMode = ImGuizmo::WORLD; - } - if (ImGui::IsKeyPressed(ImGuiKey_S) && ImGui::IsKeyPressed(ImGuiKey_LeftShift)) - useSnap = !useSnap; - ImGui::Checkbox("##UseSnap", &useSnap); - ImGui::SameLine(); - - switch (mCurrentGizmoOperation) - { - case ImGuizmo::TRANSLATE: - ImGui::InputFloat3("Snap", &snap[0]); - break; - case ImGuizmo::ROTATE: - ImGui::InputFloat("Angle Snap", &snap[0]); - break; - case ImGuizmo::SCALE: - ImGui::InputFloat("Scale Snap", &snap[0]); - break; - } - ImGui::Checkbox("Bound Sizing", &boundSizing); - if (boundSizing) - { - ImGui::PushID(3); - ImGui::Checkbox("##BoundSizing", &boundSizingSnap); - ImGui::SameLine(); - ImGui::InputFloat3("Snap", boundsSnap); - ImGui::PopID(); - } - } - - ImGuiIO& io = ImGui::GetIO(); - float viewManipulateRight = io.DisplaySize.x; - float viewManipulateTop = 0; - static ImGuiWindowFlags gizmoWindowFlags = 0; - - /* - for the "useWindow" case we just render to a gui area, - otherwise to fake full screen transparent window - - note that for both cases we make sure gizmo being - rendered is aligned to our texture scene using - imgui "cursor" screen positions - */ - - SImResourceInfo info; - info.textureID = OfflineSceneTextureIx; - info.samplerIx = (uint16_t)nbl::ext::imgui::UI::DefaultSamplerIx::USER; - - if (params.useWindow) - { - ImGui::SetNextWindowSize(ImVec2(800, 400), ImGuiCond_Appearing); - ImGui::SetNextWindowPos(ImVec2(400, 20), ImGuiCond_Appearing); - ImGui::PushStyleColor(ImGuiCol_WindowBg, (ImVec4)ImColor(0.35f, 0.3f, 0.3f)); - ImGui::Begin("Gizmo", 0, gizmoWindowFlags); - ImGuizmo::SetDrawlist(); - - ImVec2 contentRegionSize = ImGui::GetContentRegionAvail(); - ImVec2 windowPos = ImGui::GetWindowPos(); - ImVec2 cursorPos = ImGui::GetCursorScreenPos(); - - ImGui::Image(info, contentRegionSize); - ImGuizmo::SetRect(cursorPos.x, cursorPos.y, contentRegionSize.x, contentRegionSize.y); - - viewManipulateRight = cursorPos.x + contentRegionSize.x; - viewManipulateTop = cursorPos.y; - - ImGuiWindow* window = ImGui::GetCurrentWindow(); - gizmoWindowFlags = (ImGui::IsWindowHovered() && ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max) ? ImGuiWindowFlags_NoMove : 0); - } - else - { - ImGui::SetNextWindowPos(ImVec2(0, 0)); - ImGui::SetNextWindowSize(io.DisplaySize); - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); // fully transparent fake window - ImGui::Begin("FullScreenWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs); - - ImVec2 contentRegionSize = ImGui::GetContentRegionAvail(); - ImVec2 cursorPos = ImGui::GetCursorScreenPos(); - - ImGui::Image(info, contentRegionSize); - ImGuizmo::SetRect(cursorPos.x, cursorPos.y, contentRegionSize.x, contentRegionSize.y); - - viewManipulateRight = cursorPos.x + contentRegionSize.x; - viewManipulateTop = cursorPos.y; - } - - ImGuizmo::Manipulate(cameraView, cameraProjection, mCurrentGizmoOperation, mCurrentGizmoMode, matrix, NULL, useSnap ? &snap[0] : NULL, boundSizing ? bounds : NULL, boundSizingSnap ? boundsSnap : NULL); - - if(params.enableViewManipulate) - ImGuizmo::ViewManipulate(cameraView, params.camDistance, ImVec2(viewManipulateRight - 128, viewManipulateTop), ImVec2(128, 128), 0x10101010); - - ImGui::End(); - ImGui::PopStyleColor(); -} - -#endif // __NBL_THIS_EXAMPLE_TRANSFORM_H_INCLUDED__ \ No newline at end of file diff --git a/34_DebugDraw/src/transform.cpp b/34_DebugDraw/src/transform.cpp deleted file mode 100644 index e69de29bb..000000000 From 17b53a858ce5dc0e47878ca9a9e9fb9fe927d86e Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 1 Jul 2025 14:46:04 +0700 Subject: [PATCH 05/18] draw aabb from push constant --- 34_DebugDraw/app_resources/simple.vertex.hlsl | 4 +- 34_DebugDraw/main.cpp | 52 +++++++++++++++---- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/34_DebugDraw/app_resources/simple.vertex.hlsl b/34_DebugDraw/app_resources/simple.vertex.hlsl index 9651154bd..5f7b9c429 100644 --- a/34_DebugDraw/app_resources/simple.vertex.hlsl +++ b/34_DebugDraw/app_resources/simple.vertex.hlsl @@ -12,9 +12,9 @@ PSInput main(uint vertexID : SV_VertexID) { PSInput output; - float32_t4 vertex = (bda::__ptr::create(pc.pVertices) + vertexID).deref_restrict().load(); + float32_t3 vertex = (bda::__ptr::create(pc.pVertices) + vertexID).deref_restrict().load(); - output.position = mul(pc.MVP, vertex); + output.position = mul(pc.MVP, float32_t4(vertex, 1)); output.color = float32_t4(1, 0, 0, 1); return output; diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 3c29b258b..68fa6593c 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -117,8 +117,9 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti m_surface->recreateSwapchain(); { + std::array vertices = getVerticesFromAABB(testAABB); IGPUBuffer::SCreationParams params; - params.size = sizeof(float32_t4) * vertices.size(); + params.size = sizeof(float32_t3) * vertices.size(); params.usage = IGPUBuffer::EUF_STORAGE_BUFFER_BIT | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; m_utils->createFilledDeviceLocalBufferOnDedMem( @@ -286,7 +287,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti cmdbuf->bindGraphicsPipeline(m_pipeline.get()); cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); cmdbuf->setLineWidth(1.f); - cmdbuf->draw(vertices.size(), 1, 0, 0); + cmdbuf->draw(24, 1, 0, 0); cmdbuf->endRenderPass(); } @@ -360,6 +361,45 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti } private: + std::array getVerticesFromAABB(core::aabbox3d& aabb) + { + const auto& pMin = aabb.MinEdge; + const auto& pMax = aabb.MaxEdge; + + std::array vertices; + vertices[0] = float32_t3(pMin.X, pMin.Y, pMin.Z); + vertices[1] = float32_t3(pMax.X, pMin.Y, pMin.Z); + vertices[2] = float32_t3(pMin.X, pMin.Y, pMin.Z); + vertices[3] = float32_t3(pMin.X, pMin.Y, pMax.Z); + + vertices[4] = float32_t3(pMax.X, pMin.Y, pMax.Z); + vertices[5] = float32_t3(pMax.X, pMin.Y, pMin.Z); + vertices[6] = float32_t3(pMax.X, pMin.Y, pMax.Z); + vertices[7] = float32_t3(pMin.X, pMin.Y, pMax.Z); + + vertices[8] = float32_t3(pMin.X, pMax.Y, pMin.Z); + vertices[9] = float32_t3(pMax.X, pMax.Y, pMin.Z); + vertices[10] = float32_t3(pMin.X, pMax.Y, pMin.Z); + vertices[11] = float32_t3(pMin.X, pMax.Y, pMax.Z); + + vertices[12] = float32_t3(pMax.X, pMax.Y, pMax.Z); + vertices[13] = float32_t3(pMax.X, pMax.Y, pMin.Z); + vertices[14] = float32_t3(pMax.X, pMax.Y, pMax.Z); + vertices[15] = float32_t3(pMin.X, pMax.Y, pMax.Z); + + vertices[16] = float32_t3(pMin.X, pMin.Y, pMin.Z); + vertices[17] = float32_t3(pMin.X, pMax.Y, pMin.Z); + vertices[18] = float32_t3(pMax.X, pMin.Y, pMin.Z); + vertices[19] = float32_t3(pMax.X, pMax.Y, pMin.Z); + + vertices[20] = float32_t3(pMin.X, pMin.Y, pMax.Z); + vertices[21] = float32_t3(pMin.X, pMax.Y, pMax.Z); + vertices[22] = float32_t3(pMax.X, pMin.Y, pMax.Z); + vertices[23] = float32_t3(pMax.X, pMax.Y, pMax.Z); + + return vertices; + } + // Maximum frames which can be simultaneously submitted, used to cycle through our per-frame resources like command buffers constexpr static inline uint32_t MaxFramesInFlight = 3u; @@ -383,15 +423,9 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed - bool isPerspective = true, isLH = true, flipGizmoY = true, move = false; float fov = 60.f, zNear = 0.1f, zFar = 10000.f, moveSpeed = 1.f, rotateSpeed = 1.f; - float viewWidth = 10.f; - float camYAngle = 165.f / 180.f * 3.14159f; - float camXAngle = 32.f / 180.f * 3.14159f; - - bool firstFrame = true; - std::array vertices = { float32_t4(0,0,0,1), float32_t4(10,10,-10,1) }; + core::aabbox3d testAABB = core::aabbox3d({ 0, 0, 0 }, { 10, 10, -10 }); smart_refctd_ptr verticesBuffer; }; From a62cbed4b229e46a1ca59b4682c784d0ce467dd2 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 1 Jul 2025 16:59:46 +0700 Subject: [PATCH 06/18] move single aabb stuff into CDrawAABB --- 34_DebugDraw/include/CDrawAABB.h | 45 +++++++++++++++++- 34_DebugDraw/main.cpp | 18 ++++++-- 34_DebugDraw/src/CDrawAABB.cpp | 78 +++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 7 deletions(-) diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h index 65a8142a1..998e31b7f 100644 --- a/34_DebugDraw/include/CDrawAABB.h +++ b/34_DebugDraw/include/CDrawAABB.h @@ -2,4 +2,47 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h -// TODO move this into nabla \ No newline at end of file +// TODO move this into nabla + +#include "nbl/video/declarations.h" +#include "nbl/builtin/hlsl/cpp_compat.hlsl" + +#ifndef _NBL_EXT_DRAW_AABB_H_ +#define _NBL_EXT_DRAW_AABB_H_ + +namespace nbl::ext::drawdebug +{ +class DrawAABB final : public core::IReferenceCounted +{ +public: + struct SCreationParameters + { + asset::SPushConstantRange pushConstantRange; + }; + + // creates an instance that draws one AABB via push constant + static core::smart_refctd_ptr create(SCreationParameters&& params); + + // creates an instance that draws multiple AABBs using streaming buffer + // TODO + + // creates default pipeline layout for push constant version + static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange); + + inline const SCreationParameters& getCreationParameters() const { return m_creationParams; } + + // records draw command for single AABB, user has to set pipeline outside + bool renderSingle(video::IGPUCommandBuffer* commandBuffer); + + static std::array getVerticesFromAABB(const core::aabbox3d& aabb); + +protected: + DrawAABB(SCreationParameters&& _params); + ~DrawAABB() override; + +private: + SCreationParameters m_creationParams; +}; +} + +#endif diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 68fa6593c..5af301f35 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -116,8 +116,17 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti m_winMgr->setWindowSize(m_window.get(), WIN_W, WIN_H); m_surface->recreateSwapchain(); + { + ext::drawdebug::DrawAABB::SCreationParameters params; + params.pushConstantRange = { + .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, + .offset = 0, + .size = sizeof(SPushConstants) + }; + drawAABB = ext::drawdebug::DrawAABB::create(std::move(params)); + } { - std::array vertices = getVerticesFromAABB(testAABB); + auto vertices = ext::drawdebug::DrawAABB::getVerticesFromAABB(testAABB); IGPUBuffer::SCreationParams params; params.size = sizeof(float32_t3) * vertices.size(); params.usage = IGPUBuffer::EUF_STORAGE_BUFFER_BIT | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; @@ -152,8 +161,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti auto vertexShader = compileShader("app_resources/simple.vertex.hlsl"); auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); - const asset::SPushConstantRange pcRange = { .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, .offset = 0, .size = sizeof(SPushConstants) }; - const auto pipelineLayout = m_device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); + const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), drawAABB->getCreationParameters().pushConstantRange); IGPUGraphicsPipeline::SCreationParams params[1] = {}; params[0].layout = pipelineLayout.get(); @@ -286,8 +294,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti cmdbuf->beginRenderPass(beginInfo, IGPUCommandBuffer::SUBPASS_CONTENTS::INLINE); cmdbuf->bindGraphicsPipeline(m_pipeline.get()); cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); - cmdbuf->setLineWidth(1.f); - cmdbuf->draw(24, 1, 0, 0); + drawAABB->renderSingle(cmdbuf); cmdbuf->endRenderPass(); } @@ -425,6 +432,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti float fov = 60.f, zNear = 0.1f, zFar = 10000.f, moveSpeed = 1.f, rotateSpeed = 1.f; + smart_refctd_ptr drawAABB; core::aabbox3d testAABB = core::aabbox3d({ 0, 0, 0 }, { 10, 10, -10 }); smart_refctd_ptr verticesBuffer; }; diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp index 65a8142a1..8dc99f693 100644 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -2,4 +2,80 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h -// TODO move this into nabla \ No newline at end of file +// TODO move this into nabla + +#include "CDrawAABB.h" + +using namespace nbl; +using namespace hlsl; + +namespace nbl::ext::drawdebug +{ + +core::smart_refctd_ptr DrawAABB::create(SCreationParameters&& params) +{ + return core::smart_refctd_ptr(new DrawAABB(std::move(params))); +} + +DrawAABB::DrawAABB(SCreationParameters&& _params) + : m_creationParams(_params) +{ +} + +DrawAABB::~DrawAABB() +{ +} + +core::smart_refctd_ptr DrawAABB::createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange) +{ + return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); +} + +bool DrawAABB::renderSingle(video::IGPUCommandBuffer* commandBuffer) +{ + commandBuffer->setLineWidth(1.f); + commandBuffer->draw(24, 1, 0, 0); + + return true; +} + +std::array DrawAABB::getVerticesFromAABB(const core::aabbox3d& aabb) +{ + const auto& pMin = aabb.MinEdge; + const auto& pMax = aabb.MaxEdge; + + std::array vertices; + vertices[0] = float32_t3(pMin.X, pMin.Y, pMin.Z); + vertices[1] = float32_t3(pMax.X, pMin.Y, pMin.Z); + vertices[2] = float32_t3(pMin.X, pMin.Y, pMin.Z); + vertices[3] = float32_t3(pMin.X, pMin.Y, pMax.Z); + + vertices[4] = float32_t3(pMax.X, pMin.Y, pMax.Z); + vertices[5] = float32_t3(pMax.X, pMin.Y, pMin.Z); + vertices[6] = float32_t3(pMax.X, pMin.Y, pMax.Z); + vertices[7] = float32_t3(pMin.X, pMin.Y, pMax.Z); + + vertices[8] = float32_t3(pMin.X, pMax.Y, pMin.Z); + vertices[9] = float32_t3(pMax.X, pMax.Y, pMin.Z); + vertices[10] = float32_t3(pMin.X, pMax.Y, pMin.Z); + vertices[11] = float32_t3(pMin.X, pMax.Y, pMax.Z); + + vertices[12] = float32_t3(pMax.X, pMax.Y, pMax.Z); + vertices[13] = float32_t3(pMax.X, pMax.Y, pMin.Z); + vertices[14] = float32_t3(pMax.X, pMax.Y, pMax.Z); + vertices[15] = float32_t3(pMin.X, pMax.Y, pMax.Z); + + vertices[16] = float32_t3(pMin.X, pMin.Y, pMin.Z); + vertices[17] = float32_t3(pMin.X, pMax.Y, pMin.Z); + vertices[18] = float32_t3(pMax.X, pMin.Y, pMin.Z); + vertices[19] = float32_t3(pMax.X, pMax.Y, pMin.Z); + + vertices[20] = float32_t3(pMin.X, pMin.Y, pMax.Z); + vertices[21] = float32_t3(pMin.X, pMax.Y, pMax.Z); + vertices[22] = float32_t3(pMax.X, pMin.Y, pMax.Z); + vertices[23] = float32_t3(pMax.X, pMax.Y, pMax.Z); + + return vertices; +} + +} From 5fa8874cca7ed3e7162792d2f68a020b99309322 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 2 Jul 2025 12:06:05 +0700 Subject: [PATCH 07/18] default pipeline creation func --- 34_DebugDraw/include/CDrawAABB.h | 2 ++ 34_DebugDraw/main.cpp | 15 +++------------ 34_DebugDraw/src/CDrawAABB.cpp | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h index 998e31b7f..76fc35612 100644 --- a/34_DebugDraw/include/CDrawAABB.h +++ b/34_DebugDraw/include/CDrawAABB.h @@ -29,6 +29,8 @@ class DrawAABB final : public core::IReferenceCounted // creates default pipeline layout for push constant version static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange); + static bool createDefaultPipeline(core::smart_refctd_ptr* pipeline, video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment); + inline const SCreationParameters& getCreationParameters() const { return m_creationParams; } // records draw command for single AABB, user has to set pipeline outside diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 5af301f35..089aafa00 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -163,18 +163,9 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), drawAABB->getCreationParameters().pushConstantRange); - IGPUGraphicsPipeline::SCreationParams params[1] = {}; - params[0].layout = pipelineLayout.get(); - params[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main", }; - params[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main", }; - params[0].cached = { - .primitiveAssembly = { - .primitiveType = E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, - } - }; - params[0].renderpass = renderpass; - - if (!m_device->createGraphicsPipelines(nullptr, params, &m_pipeline)) + IGPUGraphicsPipeline::SShaderSpecInfo vs = { .shader = vertexShader.get(), .entryPoint = "main" }; + IGPUGraphicsPipeline::SShaderSpecInfo fs = { .shader = fragmentShader.get(), .entryPoint = "main" }; + if (!ext::drawdebug::DrawAABB::createDefaultPipeline(&m_pipeline, m_device.get(), pipelineLayout.get(), renderpass, vs, fs)) return logFail("Graphics pipeline creation failed"); m_window->setCaption("[Nabla Engine] Debug Draw App Test Demo"); diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp index 8dc99f693..e5c18f636 100644 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -31,6 +31,22 @@ core::smart_refctd_ptr DrawAABB::createDefaultPipelin return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); } +bool DrawAABB::createDefaultPipeline(core::smart_refctd_ptr* pipeline, video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment) +{ + video::IGPUGraphicsPipeline::SCreationParams params[1] = {}; + params[0].layout = layout; + params[0].vertexShader = vertex; + params[0].fragmentShader = fragment; + params[0].cached = { + .primitiveAssembly = { + .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, + } + }; + params[0].renderpass = renderpass; + + return device->createGraphicsPipelines(nullptr, params, pipeline); +} + bool DrawAABB::renderSingle(video::IGPUCommandBuffer* commandBuffer) { commandBuffer->setLineWidth(1.f); From 704a0fba4d2f8e49cbab544f75fb9801df6568e4 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 3 Jul 2025 17:04:33 +0700 Subject: [PATCH 08/18] got streaming buffer working and drawing --- .../app_resources/multi_aabb.vertex.hlsl | 23 +++ 34_DebugDraw/main.cpp | 159 +++++++++++++++++- 2 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 34_DebugDraw/app_resources/multi_aabb.vertex.hlsl diff --git a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl new file mode 100644 index 000000000..1bd6d85e1 --- /dev/null +++ b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl @@ -0,0 +1,23 @@ +#pragma shader_stage(vertex) + +#include "simple_common.hlsl" + +struct VSInput +{ + [[vk::location(0)]] float32_t3 position : POSITION; +}; + +using namespace nbl::hlsl; + +[[vk::push_constant]] SPushConstants pc; + +[shader("vertex")] +PSInput main(VSInput input) +{ + PSInput output; + + output.position = mul(pc.MVP, float32_t4(input.position, 1)); + output.color = float32_t4(0, 1, 0, 1); + + return output; +} \ No newline at end of file diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 089aafa00..527086469 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -138,6 +138,48 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti ).move_into(verticesBuffer); } + // create streaming buffer + // TODO move into CDrawAABB + { + auto RequiredAllocateFlags = core::bitflag(video::IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT); + auto RequiredUsageFlags = core::bitflag(asset::IBuffer::EUF_INDIRECT_BUFFER_BIT) | asset::IBuffer::EUF_VERTEX_BUFFER_BIT | asset::IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; + const uint32_t minStreamingBufferAllocationSize = 128u, maxStreamingBufferAllocationAlignment = 4096u, mdiBufferDefaultSize = /* 2MB */ 1024u * 1024u * 2u; + + auto getRequiredAccessFlags = [&](const bitflag& properties) + { + bitflag flags(IDeviceMemoryAllocation::EMCAF_NO_MAPPING_ACCESS); + + if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_READABLE_BIT)) + flags |= IDeviceMemoryAllocation::EMCAF_READ; + if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_WRITABLE_BIT)) + flags |= IDeviceMemoryAllocation::EMCAF_WRITE; + + return flags; + }; + + IGPUBuffer::SCreationParams mdiCreationParams = {}; + mdiCreationParams.usage = RequiredUsageFlags; + mdiCreationParams.size = mdiBufferDefaultSize; + + auto buffer = m_device->createBuffer(std::move(mdiCreationParams)); + buffer->setObjectDebugName("MDI Upstream Buffer"); + + auto memoryReqs = buffer->getMemoryReqs(); + memoryReqs.memoryTypeBits &= m_device->getPhysicalDevice()->getUpStreamingMemoryTypeBits(); + + auto allocation = m_device->allocate(memoryReqs, buffer.get(), RequiredAllocateFlags); + { + const bool allocated = allocation.isValid(); + assert(allocated); + } + auto memory = allocation.memory; + + if (!memory->map({ 0ull, memoryReqs.size }, getRequiredAccessFlags(memory->getMemoryPropertyFlags()))) + m_logger->log("Could not map device memory!", ILogger::ELL_ERROR); + + streamingBuffer = make_smart_refctd_ptr(SBufferRange{0ull, mdiCreationParams.size, std::move(buffer)}, maxStreamingBufferAllocationAlignment, minStreamingBufferAllocationSize); + } + auto compileShader = [&](const std::string& filePath) -> smart_refctd_ptr { IAssetLoader::SAssetLoadParams lparams = {}; @@ -158,15 +200,51 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti return m_device->compileShader({ shaderSrc.get() }); }; - auto vertexShader = compileShader("app_resources/simple.vertex.hlsl"); - auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); + { + auto vertexShader = compileShader("app_resources/simple.vertex.hlsl"); + auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); + + const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), drawAABB->getCreationParameters().pushConstantRange); + + IGPUGraphicsPipeline::SShaderSpecInfo vs = { .shader = vertexShader.get(), .entryPoint = "main" }; + IGPUGraphicsPipeline::SShaderSpecInfo fs = { .shader = fragmentShader.get(), .entryPoint = "main" }; + if (!ext::drawdebug::DrawAABB::createDefaultPipeline(&m_pipeline, m_device.get(), pipelineLayout.get(), renderpass, vs, fs)) + return logFail("Graphics pipeline creation failed"); + } + { + auto vertexShader = compileShader("app_resources/multi_aabb.vertex.hlsl"); + auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); + + const auto pipelineLayout = m_device->createPipelineLayout({ &drawAABB->getCreationParameters().pushConstantRange , 1 }, nullptr, nullptr, nullptr, nullptr); - const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), drawAABB->getCreationParameters().pushConstantRange); + SVertexInputParams vertexInputParams{}; + { + vertexInputParams.enabledBindingFlags = 0b1u; + vertexInputParams.enabledAttribFlags = 0b1u; + + vertexInputParams.bindings[0].inputRate = SVertexInputBindingParams::EVIR_PER_VERTEX; + vertexInputParams.bindings[0].stride = sizeof(float32_t3); + + auto& position = vertexInputParams.attributes[0]; + position.format = EF_R32G32B32_SFLOAT; + position.relativeOffset = 0u; + position.binding = 0u; + } - IGPUGraphicsPipeline::SShaderSpecInfo vs = { .shader = vertexShader.get(), .entryPoint = "main" }; - IGPUGraphicsPipeline::SShaderSpecInfo fs = { .shader = fragmentShader.get(), .entryPoint = "main" }; - if (!ext::drawdebug::DrawAABB::createDefaultPipeline(&m_pipeline, m_device.get(), pipelineLayout.get(), renderpass, vs, fs)) - return logFail("Graphics pipeline creation failed"); + video::IGPUGraphicsPipeline::SCreationParams params[1] = {}; + params[0].layout = pipelineLayout.get(); + params[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; + params[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main" }; + params[0].cached = { + .vertexInput = vertexInputParams, + .primitiveAssembly = { + .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, + } + }; + params[0].renderpass = renderpass; + + m_device->createGraphicsPipelines(nullptr, params, &m_streamingPipeline); + } m_window->setCaption("[Nabla Engine] Debug Draw App Test Demo"); m_winMgr->show(m_window.get()); @@ -287,8 +365,70 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); drawAABB->renderSingle(cmdbuf); + cmdbuf->bindGraphicsPipeline(m_streamingPipeline.get()); + cmdbuf->pushConstants(m_streamingPipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); + + // TODO bind vertex buffer (streaming buffer) + const SBufferBinding binding = + { + .offset = 0u, + .buffer = smart_refctd_ptr(streamingBuffer.get()->getBuffer()) + }; + cmdbuf->bindVertexBuffers(0u, 1u, &binding); + + // fill streaming buffer: indirect draw command, then vertex buffer + { + auto vertices = ext::drawdebug::DrawAABB::getVerticesFromAABB(testAABB2); + uint32_t indirectDrawCount = 1u; + + using offset_t = streaming_buffer_t::size_type; + constexpr auto MdiSizes = std::to_array({ sizeof(VkDrawIndirectCommand), sizeof(float32_t3) }); + // shared nPoT alignment needs to be divisible by all smaller ones to satisfy an allocation from all + constexpr offset_t MaxAlignment = std::reduce(MdiSizes.begin(), MdiSizes.end(), 1, [](const offset_t a, const offset_t b)->offset_t {return std::lcm(a, b); }); + // allocator initialization needs us to round up to PoT + const auto MaxPOTAlignment = roundUpToPoT(MaxAlignment); + + auto* streaming = streamingBuffer.get(); + + auto* const streamingPtr = reinterpret_cast(streaming->getBufferPointer()); + assert(streamingPtr); + + using suballocator_t = core::LinearAddressAllocatorST; + offset_t inputOffset = 0u; + offset_t ImaginarySizeUpperBound = 0x1 << 30; + suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); + uint32_t indirectDrawByteOffset = imaginaryChunk.alloc_addr(sizeof(VkDrawIndirectCommand) * indirectDrawCount, sizeof(VkDrawIndirectCommand)); + uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(sizeof(float32_t3) * vertices.size(), sizeof(float32_t3)); + const uint32_t totalSize = imaginaryChunk.get_allocated_size(); + + std::chrono::steady_clock::time_point waitTill(std::chrono::years(45)); + streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); + + auto* drawIndirectIt = reinterpret_cast(streamingPtr + indirectDrawByteOffset); + for (auto i = 0u; i < indirectDrawCount; i++) + { + drawIndirectIt->firstVertex = 0; + drawIndirectIt->firstInstance = i; + drawIndirectIt->vertexCount = vertices.size(); + drawIndirectIt->instanceCount = 1; + drawIndirectIt++; + } + memcpy(streamingPtr + vertexByteOffset, vertices.data(), sizeof(vertices[0]) * vertices.size()); + + assert(!streaming->needsManualFlushOrInvalidate()); + + // TODO cmdbuf draw indirect + auto mdiBinding = binding; + mdiBinding.offset = indirectDrawByteOffset; + cmdbuf->drawIndirect(binding, 1, sizeof(VkDrawIndirectCommand)); + + const ISemaphore::SWaitInfo drawFinished = { .semaphore = m_semaphore.get(),.value = m_realFrameIx + 1u }; + streaming->multi_deallocate(1, &inputOffset, &totalSize, drawFinished); + } + cmdbuf->endRenderPass(); } + cmdbuf->endDebugMarker(); cmdbuf->end(); { @@ -404,6 +544,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti smart_refctd_ptr m_window; smart_refctd_ptr> m_surface; smart_refctd_ptr m_pipeline; + smart_refctd_ptr m_streamingPipeline; smart_refctd_ptr m_semaphore; smart_refctd_ptr m_cmdPool; uint64_t m_realFrameIx = 0; @@ -425,7 +566,11 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti smart_refctd_ptr drawAABB; core::aabbox3d testAABB = core::aabbox3d({ 0, 0, 0 }, { 10, 10, -10 }); + core::aabbox3d testAABB2 = core::aabbox3d({ 2, 4, -1 }, { 7, 8, 5 }); smart_refctd_ptr verticesBuffer; + + using streaming_buffer_t = video::StreamingTransientDataBufferST>; + smart_refctd_ptr streamingBuffer; }; NBL_MAIN_FUNC(DebugDrawSampleApp) \ No newline at end of file From a81e62f56b2fbb04f84ae7fe3b2d2cad1ef941a7 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 4 Jul 2025 11:46:23 +0700 Subject: [PATCH 09/18] draw with instances --- 34_DebugDraw/app_resources/common.hlsl | 35 ++++++++ .../app_resources/multi_aabb.vertex.hlsl | 24 +++--- 34_DebugDraw/app_resources/simple.vertex.hlsl | 2 +- 34_DebugDraw/app_resources/simple_common.hlsl | 2 +- 34_DebugDraw/main.cpp | 80 ++++++++++--------- 5 files changed, 93 insertions(+), 50 deletions(-) create mode 100644 34_DebugDraw/app_resources/common.hlsl diff --git a/34_DebugDraw/app_resources/common.hlsl b/34_DebugDraw/app_resources/common.hlsl new file mode 100644 index 000000000..e1a42d5b6 --- /dev/null +++ b/34_DebugDraw/app_resources/common.hlsl @@ -0,0 +1,35 @@ +#ifndef _DRAW_AABB_COMMON_HLSL +#define _DRAW_AABB_COMMON_HLSL + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" + +struct InstanceData +{ +#ifdef __HLSL_VERSION + float32_t3x4 transform; +#else + float transform[3*4]; +#endif + float32_t3 color; +}; + +struct SPushConstants +{ +#ifdef __HLSL_VERSION + float32_t4x4 MVP; +#else + float MVP[4*4]; +#endif + uint64_t pVertexBuffer; + uint64_t pInstanceBuffer; +}; + +#ifdef __HLSL_VERSION +struct PSInput +{ + float32_t4 position : SV_Position; + float32_t4 color : TEXCOORD0; +}; +#endif + +#endif diff --git a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl index 1bd6d85e1..37673deee 100644 --- a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl +++ b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl @@ -1,23 +1,29 @@ #pragma shader_stage(vertex) -#include "simple_common.hlsl" - -struct VSInput -{ - [[vk::location(0)]] float32_t3 position : POSITION; -}; +#include "nbl/builtin/hlsl/glsl_compat/core.hlsl" +#include "nbl/builtin/hlsl/bda/__ptr.hlsl" +#include "common.hlsl" using namespace nbl::hlsl; [[vk::push_constant]] SPushConstants pc; [shader("vertex")] -PSInput main(VSInput input) +PSInput main() { PSInput output; - output.position = mul(pc.MVP, float32_t4(input.position, 1)); - output.color = float32_t4(0, 1, 0, 1); + float32_t3 vertex = (bda::__ptr::create(pc.pVertexBuffer) + glsl::gl_VertexIndex()).deref_restrict().load(); + InstanceData instance = vk::RawBufferLoad(pc.pInstanceBuffer + sizeof(InstanceData) * glsl::gl_InstanceIndex()); + + float32_t4x4 transform; + transform[0] = instance.transform[0]; + transform[1] = instance.transform[1]; + transform[2] = instance.transform[2]; + transform[3] = float32_t4(0, 0, 0, 1); + float32_t4 position = mul(transform, float32_t4(vertex, 1)); + output.position = mul(pc.MVP, position); + output.color = float32_t4(instance.color, 1); return output; } \ No newline at end of file diff --git a/34_DebugDraw/app_resources/simple.vertex.hlsl b/34_DebugDraw/app_resources/simple.vertex.hlsl index 5f7b9c429..9e362ee75 100644 --- a/34_DebugDraw/app_resources/simple.vertex.hlsl +++ b/34_DebugDraw/app_resources/simple.vertex.hlsl @@ -5,7 +5,7 @@ using namespace nbl::hlsl; -[[vk::push_constant]] SPushConstants pc; +[[vk::push_constant]] SSimplePushConstants pc; [shader("vertex")] PSInput main(uint vertexID : SV_VertexID) diff --git a/34_DebugDraw/app_resources/simple_common.hlsl b/34_DebugDraw/app_resources/simple_common.hlsl index 5fc0d0b63..d74d64a8d 100644 --- a/34_DebugDraw/app_resources/simple_common.hlsl +++ b/34_DebugDraw/app_resources/simple_common.hlsl @@ -3,7 +3,7 @@ #include "nbl/builtin/hlsl/cpp_compat.hlsl" -struct SPushConstants +struct SSimplePushConstants { #ifdef __HLSL_VERSION float32_t4x4 MVP; diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 527086469..237b99fac 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -4,6 +4,7 @@ #include "common.hpp" #include "app_resources/simple_common.hlsl" +#include "app_resources/common.hlsl" class DebugDrawSampleApp final : public SimpleWindowedApplication, public BuiltinResourcesApplication { @@ -121,7 +122,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti params.pushConstantRange = { .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, .offset = 0, - .size = sizeof(SPushConstants) + .size = sizeof(SSimplePushConstants) }; drawAABB = ext::drawdebug::DrawAABB::create(std::move(params)); } @@ -214,8 +215,13 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti { auto vertexShader = compileShader("app_resources/multi_aabb.vertex.hlsl"); auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); + SPushConstantRange pcRange = { + .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, + .offset = 0, + .size = sizeof(SPushConstants) + }; - const auto pipelineLayout = m_device->createPipelineLayout({ &drawAABB->getCreationParameters().pushConstantRange , 1 }, nullptr, nullptr, nullptr, nullptr); + const auto pipelineLayout = m_device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); SVertexInputParams vertexInputParams{}; { @@ -236,14 +242,14 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti params[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; params[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main" }; params[0].cached = { - .vertexInput = vertexInputParams, .primitiveAssembly = { .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, } }; params[0].renderpass = renderpass; - m_device->createGraphicsPipelines(nullptr, params, &m_streamingPipeline); + if (!m_device->createGraphicsPipelines(nullptr, params, &m_streamingPipeline)) + return logFail("Could not create streaming pipeline!"); } m_window->setCaption("[Nabla Engine] Debug Draw App Test Demo"); @@ -356,33 +362,24 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti .renderArea = currentRenderArea }; - SPushConstants pc; - memcpy(pc.MVP, modelViewProjectionMatrix.pointer(), sizeof(pc.MVP)); - pc.pVertices = verticesBuffer->getDeviceAddress(); - - cmdbuf->beginRenderPass(beginInfo, IGPUCommandBuffer::SUBPASS_CONTENTS::INLINE); - cmdbuf->bindGraphicsPipeline(m_pipeline.get()); - cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); - drawAABB->renderSingle(cmdbuf); - - cmdbuf->bindGraphicsPipeline(m_streamingPipeline.get()); - cmdbuf->pushConstants(m_streamingPipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); - - // TODO bind vertex buffer (streaming buffer) - const SBufferBinding binding = { - .offset = 0u, - .buffer = smart_refctd_ptr(streamingBuffer.get()->getBuffer()) - }; - cmdbuf->bindVertexBuffers(0u, 1u, &binding); + SSimplePushConstants pc; + memcpy(pc.MVP, modelViewProjectionMatrix.pointer(), sizeof(pc.MVP)); + pc.pVertices = verticesBuffer->getDeviceAddress(); + + cmdbuf->beginRenderPass(beginInfo, IGPUCommandBuffer::SUBPASS_CONTENTS::INLINE); + cmdbuf->bindGraphicsPipeline(m_pipeline.get()); + cmdbuf->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SSimplePushConstants), &pc); + drawAABB->renderSingle(cmdbuf); + } // fill streaming buffer: indirect draw command, then vertex buffer { auto vertices = ext::drawdebug::DrawAABB::getVerticesFromAABB(testAABB2); - uint32_t indirectDrawCount = 1u; + uint32_t instanceCount = 4u; using offset_t = streaming_buffer_t::size_type; - constexpr auto MdiSizes = std::to_array({ sizeof(VkDrawIndirectCommand), sizeof(float32_t3) }); + constexpr auto MdiSizes = std::to_array({ sizeof(float32_t3), sizeof(InstanceData) }); // shared nPoT alignment needs to be divisible by all smaller ones to satisfy an allocation from all constexpr offset_t MaxAlignment = std::reduce(MdiSizes.begin(), MdiSizes.end(), 1, [](const offset_t a, const offset_t b)->offset_t {return std::lcm(a, b); }); // allocator initialization needs us to round up to PoT @@ -397,30 +394,35 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti offset_t inputOffset = 0u; offset_t ImaginarySizeUpperBound = 0x1 << 30; suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); - uint32_t indirectDrawByteOffset = imaginaryChunk.alloc_addr(sizeof(VkDrawIndirectCommand) * indirectDrawCount, sizeof(VkDrawIndirectCommand)); uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(sizeof(float32_t3) * vertices.size(), sizeof(float32_t3)); + uint32_t instancesByteOffset = imaginaryChunk.alloc_addr(sizeof(InstanceData) * instanceCount, sizeof(InstanceData)); const uint32_t totalSize = imaginaryChunk.get_allocated_size(); std::chrono::steady_clock::time_point waitTill(std::chrono::years(45)); streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); - auto* drawIndirectIt = reinterpret_cast(streamingPtr + indirectDrawByteOffset); - for (auto i = 0u; i < indirectDrawCount; i++) + memcpy(streamingPtr + vertexByteOffset, vertices.data(), sizeof(vertices[0]) * vertices.size()); + auto* instancesIt = reinterpret_cast(streamingPtr + instancesByteOffset); + for (auto i = 0u; i < instanceCount; i++) { - drawIndirectIt->firstVertex = 0; - drawIndirectIt->firstInstance = i; - drawIndirectIt->vertexCount = vertices.size(); - drawIndirectIt->instanceCount = 1; - drawIndirectIt++; + core::matrix3x4SIMD instanceTransform; + instanceTransform.setTranslation(core::vectorSIMDf(i, 0, i, 0)); + instanceTransform.setScale(core::vectorSIMDf(i, i, i)); + memcpy(instancesIt->transform, instanceTransform.pointer(), sizeof(core::matrix3x4SIMD)); + instancesIt->color = float32_t3(i * 0.2, 1, 0); + instancesIt++; } - memcpy(streamingPtr + vertexByteOffset, vertices.data(), sizeof(vertices[0]) * vertices.size()); assert(!streaming->needsManualFlushOrInvalidate()); - // TODO cmdbuf draw indirect - auto mdiBinding = binding; - mdiBinding.offset = indirectDrawByteOffset; - cmdbuf->drawIndirect(binding, 1, sizeof(VkDrawIndirectCommand)); + SPushConstants pc; + memcpy(pc.MVP, modelViewProjectionMatrix.pointer(), sizeof(pc.MVP)); + pc.pVertexBuffer = streamingBuffer->getBuffer()->getDeviceAddress() + vertexByteOffset; + pc.pInstanceBuffer = streamingBuffer->getBuffer()->getDeviceAddress() + instancesByteOffset; + + cmdbuf->bindGraphicsPipeline(m_streamingPipeline.get()); + cmdbuf->pushConstants(m_streamingPipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); + cmdbuf->draw(vertices.size(), instanceCount, 0, 0); const ISemaphore::SWaitInfo drawFinished = { .semaphore = m_semaphore.get(),.value = m_realFrameIx + 1u }; streaming->multi_deallocate(1, &inputOffset, &totalSize, drawFinished); @@ -565,8 +567,8 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti float fov = 60.f, zNear = 0.1f, zFar = 10000.f, moveSpeed = 1.f, rotateSpeed = 1.f; smart_refctd_ptr drawAABB; - core::aabbox3d testAABB = core::aabbox3d({ 0, 0, 0 }, { 10, 10, -10 }); - core::aabbox3d testAABB2 = core::aabbox3d({ 2, 4, -1 }, { 7, 8, 5 }); + core::aabbox3d testAABB = core::aabbox3d({ -5, -5, -5 }, { 10, 10, -10 }); + core::aabbox3d testAABB2 = core::aabbox3d({ 0, 0, 0 }, { 1, 1, 1 }); smart_refctd_ptr verticesBuffer; using streaming_buffer_t = video::StreamingTransientDataBufferST>; From da63edf598390448a2cb5835b61ecb38ec8393c4 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 4 Jul 2025 11:49:38 +0700 Subject: [PATCH 10/18] minor bug fix in creating instances --- 34_DebugDraw/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 237b99fac..40f265ae3 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -376,7 +376,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti // fill streaming buffer: indirect draw command, then vertex buffer { auto vertices = ext::drawdebug::DrawAABB::getVerticesFromAABB(testAABB2); - uint32_t instanceCount = 4u; + uint32_t instanceCount = 5u; using offset_t = streaming_buffer_t::size_type; constexpr auto MdiSizes = std::to_array({ sizeof(float32_t3), sizeof(InstanceData) }); @@ -407,7 +407,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti { core::matrix3x4SIMD instanceTransform; instanceTransform.setTranslation(core::vectorSIMDf(i, 0, i, 0)); - instanceTransform.setScale(core::vectorSIMDf(i, i, i)); + instanceTransform.setScale(core::vectorSIMDf(i+1, i+1, i+1)); memcpy(instancesIt->transform, instanceTransform.pointer(), sizeof(core::matrix3x4SIMD)); instancesIt->color = float32_t3(i * 0.2, 1, 0); instancesIt++; From 9ae72f51e507e9e9a579dd463db6fac1ae4f866c Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 4 Jul 2025 14:36:11 +0700 Subject: [PATCH 11/18] move handling instances to CDrawAABB --- 34_DebugDraw/include/CDrawAABB.h | 13 ++++++++++--- 34_DebugDraw/src/CDrawAABB.cpp | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h index 76fc35612..68704a81b 100644 --- a/34_DebugDraw/include/CDrawAABB.h +++ b/34_DebugDraw/include/CDrawAABB.h @@ -4,12 +4,13 @@ // TODO move this into nabla -#include "nbl/video/declarations.h" -#include "nbl/builtin/hlsl/cpp_compat.hlsl" - #ifndef _NBL_EXT_DRAW_AABB_H_ #define _NBL_EXT_DRAW_AABB_H_ +#include "nbl/video/declarations.h" +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include "../app_resources/common.hlsl" + namespace nbl::ext::drawdebug { class DrawAABB final : public core::IReferenceCounted @@ -38,12 +39,18 @@ class DrawAABB final : public core::IReferenceCounted static std::array getVerticesFromAABB(const core::aabbox3d& aabb); + void addAABB(const core::aabbox3d& aabb, const hlsl::float32_t3& color = { 1,0,0 }); + protected: DrawAABB(SCreationParameters&& _params); ~DrawAABB() override; private: SCreationParameters m_creationParams; + + std::vector m_instances; + std::array m_unitVertices; + constexpr static inline core::aabbox3d UnitAABB = core::aabbox3d({ 0, 0, 0 }, { 1, 1, 1 }); }; } diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp index e5c18f636..01c3cc550 100644 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -94,4 +94,18 @@ std::array DrawAABB::getVerticesFromAABB(const core::aabbox3d& aabb, const hlsl::float32_t3& color) +{ + InstanceData instance; + instance.color = color; + + core::matrix3x4SIMD instanceTransform; + instanceTransform.setTranslation(core::vectorSIMDf(aabb.MinEdge.X, aabb.MinEdge.Y, aabb.MinEdge.Z, 0)); + const auto diagonal = aabb.MaxEdge - aabb.MinEdge; + instanceTransform.setScale(core::vectorSIMDf(diagonal.X, diagonal.Y, diagonal.Z)); + memcpy(instance.transform, instanceTransform.pointer(), sizeof(core::matrix3x4SIMD)); + + m_instances.push_back(instance); +} + } From 7a22eef770a597526967c0ced0146e86e5d2bf07 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 4 Jul 2025 17:05:34 +0700 Subject: [PATCH 12/18] moved most important streaming stuff to CDrawAABB --- 34_DebugDraw/app_resources/common.hlsl | 2 +- 34_DebugDraw/include/CDrawAABB.h | 36 ++++-- 34_DebugDraw/main.cpp | 30 ++--- 34_DebugDraw/src/CDrawAABB.cpp | 168 ++++++++++++++++++++++++- 4 files changed, 201 insertions(+), 35 deletions(-) diff --git a/34_DebugDraw/app_resources/common.hlsl b/34_DebugDraw/app_resources/common.hlsl index e1a42d5b6..b7690b097 100644 --- a/34_DebugDraw/app_resources/common.hlsl +++ b/34_DebugDraw/app_resources/common.hlsl @@ -10,7 +10,7 @@ struct InstanceData #else float transform[3*4]; #endif - float32_t3 color; + nbl::hlsl::float32_t3 color; }; struct SPushConstants diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h index 68704a81b..33ff1b1f6 100644 --- a/34_DebugDraw/include/CDrawAABB.h +++ b/34_DebugDraw/include/CDrawAABB.h @@ -16,9 +16,25 @@ namespace nbl::ext::drawdebug class DrawAABB final : public core::IReferenceCounted { public: - struct SCreationParameters + struct SCachedCreationParameters + { + using streaming_buffer_t = video::StreamingTransientDataBufferST>; + + static constexpr inline auto RequiredAllocateFlags = core::bitflag(video::IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT); + static constexpr inline auto RequiredUsageFlags = core::bitflag(asset::IBuffer::EUF_STORAGE_BUFFER_BIT) | asset::IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; + + core::smart_refctd_ptr utilities; + + //! optional, default MDI buffer allocated if not provided + core::smart_refctd_ptr streamingBuffer = nullptr; + }; + + struct SCreationParameters : SCachedCreationParameters { asset::SPushConstantRange pushConstantRange; + + core::smart_refctd_ptr pipelineLayout; + core::smart_refctd_ptr renderpass = nullptr; }; // creates an instance that draws one AABB via push constant @@ -30,27 +46,33 @@ class DrawAABB final : public core::IReferenceCounted // creates default pipeline layout for push constant version static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange); - static bool createDefaultPipeline(core::smart_refctd_ptr* pipeline, video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment); + static smart_refctd_ptr createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment); - inline const SCreationParameters& getCreationParameters() const { return m_creationParams; } + inline const SCachedCreationParameters& getCreationParameters() const { return m_cachedCreationParams; } // records draw command for single AABB, user has to set pipeline outside bool renderSingle(video::IGPUCommandBuffer* commandBuffer); + bool render(video::IGPUCommandBuffer* commandBuffer, ISemaphore::SWaitInfo waitInfo, float* cameraMat3x4); + static std::array getVerticesFromAABB(const core::aabbox3d& aabb); void addAABB(const core::aabbox3d& aabb, const hlsl::float32_t3& color = { 1,0,0 }); protected: - DrawAABB(SCreationParameters&& _params); + DrawAABB(SCreationParameters&& _params, smart_refctd_ptr pipeline); ~DrawAABB() override; private: - SCreationParameters m_creationParams; + static smart_refctd_ptr createPipeline(SCreationParameters& params); + static bool createStreamingBuffer(SCreationParameters& params); std::vector m_instances; - std::array m_unitVertices; - constexpr static inline core::aabbox3d UnitAABB = core::aabbox3d({ 0, 0, 0 }, { 1, 1, 1 }); + std::array m_unitAABBVertices; + + SCachedCreationParameters m_cachedCreationParams; + + core::smart_refctd_ptr m_pipeline; }; } diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 40f265ae3..edf849657 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -117,13 +117,14 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti m_winMgr->setWindowSize(m_window.get(), WIN_W, WIN_H); m_surface->recreateSwapchain(); + SPushConstantRange simplePcRange = { + .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, + .offset = 0, + .size = sizeof(SSimplePushConstants) + }; { ext::drawdebug::DrawAABB::SCreationParameters params; - params.pushConstantRange = { - .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, - .offset = 0, - .size = sizeof(SSimplePushConstants) - }; + params.pushConstantRange = simplePcRange; drawAABB = ext::drawdebug::DrawAABB::create(std::move(params)); } { @@ -205,11 +206,12 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti auto vertexShader = compileShader("app_resources/simple.vertex.hlsl"); auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); - const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), drawAABB->getCreationParameters().pushConstantRange); + const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), simplePcRange); IGPUGraphicsPipeline::SShaderSpecInfo vs = { .shader = vertexShader.get(), .entryPoint = "main" }; IGPUGraphicsPipeline::SShaderSpecInfo fs = { .shader = fragmentShader.get(), .entryPoint = "main" }; - if (!ext::drawdebug::DrawAABB::createDefaultPipeline(&m_pipeline, m_device.get(), pipelineLayout.get(), renderpass, vs, fs)) + m_pipeline = ext::drawdebug::DrawAABB::createDefaultPipeline(m_device.get(), pipelineLayout.get(), renderpass, vs, fs); + if (!m_pipeline) return logFail("Graphics pipeline creation failed"); } { @@ -223,20 +225,6 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti const auto pipelineLayout = m_device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); - SVertexInputParams vertexInputParams{}; - { - vertexInputParams.enabledBindingFlags = 0b1u; - vertexInputParams.enabledAttribFlags = 0b1u; - - vertexInputParams.bindings[0].inputRate = SVertexInputBindingParams::EVIR_PER_VERTEX; - vertexInputParams.bindings[0].stride = sizeof(float32_t3); - - auto& position = vertexInputParams.attributes[0]; - position.format = EF_R32G32B32_SFLOAT; - position.relativeOffset = 0u; - position.binding = 0u; - } - video::IGPUGraphicsPipeline::SCreationParams params[1] = {}; params[0].layout = pipelineLayout.get(); params[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp index 01c3cc550..ae57952ce 100644 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -7,6 +7,10 @@ #include "CDrawAABB.h" using namespace nbl; +using namespace core; +using namespace video; +using namespace system; +using namespace asset; using namespace hlsl; namespace nbl::ext::drawdebug @@ -14,25 +18,131 @@ namespace nbl::ext::drawdebug core::smart_refctd_ptr DrawAABB::create(SCreationParameters&& params) { - return core::smart_refctd_ptr(new DrawAABB(std::move(params))); + auto* const logger = params.utilities->getLogger(); + + auto pipeline = createPipeline(params); + if (!pipeline) + { + logger->log("Failed to create pipeline!", ILogger::ELL_ERROR); + return nullptr; + } + + if (!createStreamingBuffer(params)) + { + logger->log("Failed to create streaming buffer!", ILogger::ELL_ERROR); + return nullptr; + } + + return core::smart_refctd_ptr(new DrawAABB(std::move(params), pipeline)); } -DrawAABB::DrawAABB(SCreationParameters&& _params) - : m_creationParams(_params) +DrawAABB::DrawAABB(SCreationParameters&& params, smart_refctd_ptr pipeline) + : m_cachedCreationParams(std::move(params)), m_pipeline(pipeline) { + const auto unitAABB = core::aabbox3d({ 0, 0, 0 }, { 1, 1, 1 }); + m_unitAABBVertices = getVerticesFromAABB(unitAABB); } DrawAABB::~DrawAABB() { } +smart_refctd_ptr DrawAABB::createPipeline(SCreationParameters& params) +{ + video::IGPUGraphicsPipeline::SCreationParams pipelineParams[1] = {}; + pipelineParams[0].layout = params.pipelineLayout.get(); + pipelineParams[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; + pipelineParams[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main" }; + pipelineParams[0].cached = { + .primitiveAssembly = { + .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, + } + }; + pipelineParams[0].renderpass = params.renderpass.get(); + + smart_refctd_ptr pipeline; + params.utilities->getLogicalDevice()->createGraphicsPipelines(nullptr, pipelineParams, &pipeline); + if (!pipeline) + { + params.utilities->getLogger()->log("Could not create streaming pipeline!", ILogger::ELL_ERROR); + return nullptr; + } + + return pipeline; +} + +bool DrawAABB::createStreamingBuffer(SCreationParameters& params) +{ + const uint32_t minStreamingBufferAllocationSize = 128u, maxStreamingBufferAllocationAlignment = 4096u, mdiBufferDefaultSize = /* 2MB */ 1024u * 1024u * 2u; + + auto getRequiredAccessFlags = [&](const bitflag& properties) + { + bitflag flags(IDeviceMemoryAllocation::EMCAF_NO_MAPPING_ACCESS); + + if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_READABLE_BIT)) + flags |= IDeviceMemoryAllocation::EMCAF_READ; + if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_WRITABLE_BIT)) + flags |= IDeviceMemoryAllocation::EMCAF_WRITE; + + return flags; + }; + + if (!params.streamingBuffer) + { + IGPUBuffer::SCreationParams mdiCreationParams = {}; + mdiCreationParams.usage = SCachedCreationParameters::RequiredUsageFlags; + mdiCreationParams.size = mdiBufferDefaultSize; + + auto buffer = params.utilities->getLogicalDevice()->createBuffer(std::move(mdiCreationParams)); + buffer->setObjectDebugName("AABB Streaming Buffer"); + + auto memoryReqs = buffer->getMemoryReqs(); + memoryReqs.memoryTypeBits &= params.utilities->getLogicalDevice()->getPhysicalDevice()->getUpStreamingMemoryTypeBits(); + + auto allocation = params.utilities->getLogicalDevice()->allocate(memoryReqs, buffer.get(), SCachedCreationParameters::RequiredAllocateFlags); + { + const bool allocated = allocation.isValid(); + assert(allocated); + } + auto memory = allocation.memory; + + if (!memory->map({ 0ull, memoryReqs.size }, getRequiredAccessFlags(memory->getMemoryPropertyFlags()))) + params.utilities->getLogger()->log("Could not map device memory!", ILogger::ELL_ERROR); + + params.streamingBuffer = make_smart_refctd_ptr(SBufferRange{0ull, mdiCreationParams.size, std::move(buffer)}, maxStreamingBufferAllocationAlignment, minStreamingBufferAllocationSize); + } + + auto buffer = params.streamingBuffer->getBuffer(); + auto binding = buffer->getBoundMemory(); + + const auto validation = std::to_array + ({ + std::make_pair(buffer->getCreationParams().usage.hasFlags(SCachedCreationParameters::RequiredUsageFlags), "Streaming buffer must be created with IBuffer::EUF_STORAGE_BUFFER_BIT | IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT enabled!"), + std::make_pair(bool(buffer->getMemoryReqs().memoryTypeBits & params.utilities->getLogicalDevice()->getPhysicalDevice()->getUpStreamingMemoryTypeBits()), "Streaming buffer must have up-streaming memory type bits enabled!"), + std::make_pair(binding.memory->getAllocateFlags().hasFlags(SCachedCreationParameters::RequiredAllocateFlags), "Streaming buffer's memory must be allocated with IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT enabled!"), + std::make_pair(binding.memory->isCurrentlyMapped(), "Streaming buffer's memory must be mapped!"), // streaming buffer contructor already validates it, but cannot assume user won't unmap its own buffer for some reason (sorry if you have just hit it) + std::make_pair(binding.memory->getCurrentMappingAccess().hasFlags(getRequiredAccessFlags(binding.memory->getMemoryPropertyFlags())), "Streaming buffer's memory current mapping access flags don't meet requirements!") + }); + + for (const auto& [ok, error] : validation) + if (!ok) + { + params.utilities->getLogger()->log(error, ILogger::ELL_ERROR); + return false; + } + + return true; +} + core::smart_refctd_ptr DrawAABB::createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange) { return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); } -bool DrawAABB::createDefaultPipeline(core::smart_refctd_ptr* pipeline, video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment) +smart_refctd_ptr DrawAABB::createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment) { + smart_refctd_ptr pipeline; + video::IGPUGraphicsPipeline::SCreationParams params[1] = {}; params[0].layout = layout; params[0].vertexShader = vertex; @@ -44,10 +154,12 @@ bool DrawAABB::createDefaultPipeline(core::smart_refctd_ptrcreateGraphicsPipelines(nullptr, params, pipeline); + device->createGraphicsPipelines(nullptr, params, &pipeline); + + return pipeline; } -bool DrawAABB::renderSingle(video::IGPUCommandBuffer* commandBuffer) +bool DrawAABB::renderSingle(IGPUCommandBuffer* commandBuffer) { commandBuffer->setLineWidth(1.f); commandBuffer->draw(24, 1, 0, 0); @@ -55,6 +167,50 @@ bool DrawAABB::renderSingle(video::IGPUCommandBuffer* commandBuffer) return true; } +bool DrawAABB::render(IGPUCommandBuffer* commandBuffer, ISemaphore::SWaitInfo waitInfo, float* cameraMat3x4) +{ + using offset_t = SCachedCreationParameters::streaming_buffer_t::size_type; + constexpr auto MdiSizes = std::to_array({ sizeof(float32_t3), sizeof(InstanceData) }); + // shared nPoT alignment needs to be divisible by all smaller ones to satisfy an allocation from all + constexpr offset_t MaxAlignment = std::reduce(MdiSizes.begin(), MdiSizes.end(), 1, [](const offset_t a, const offset_t b)->offset_t {return std::lcm(a, b); }); + // allocator initialization needs us to round up to PoT + const auto MaxPOTAlignment = roundUpToPoT(MaxAlignment); + + auto* streaming = m_cachedCreationParams.streamingBuffer.get(); + + auto* const streamingPtr = reinterpret_cast(streaming->getBufferPointer()); + assert(streamingPtr); + + using suballocator_t = core::LinearAddressAllocatorST; + offset_t inputOffset = 0u; + offset_t ImaginarySizeUpperBound = 0x1 << 30; + suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); + uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(sizeof(float32_t3) * m_unitAABBVertices.size(), sizeof(float32_t3)); + uint32_t instancesByteOffset = imaginaryChunk.alloc_addr(sizeof(InstanceData) * m_instances.size(), sizeof(InstanceData)); + const uint32_t totalSize = imaginaryChunk.get_allocated_size(); + + std::chrono::steady_clock::time_point waitTill(std::chrono::years(45)); + streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); + + memcpy(streamingPtr + vertexByteOffset, m_unitAABBVertices.data(), sizeof(m_unitAABBVertices[0]) * m_unitAABBVertices.size()); + memcpy(streamingPtr + instancesByteOffset, m_instances.data(), sizeof(m_instances[0]) * m_instances.size()); + + assert(!streaming->needsManualFlushOrInvalidate()); + + SPushConstants pc; + memcpy(pc.MVP, cameraMat3x4, sizeof(pc.MVP)); + pc.pVertexBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + vertexByteOffset; + pc.pInstanceBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + instancesByteOffset; + + commandBuffer->bindGraphicsPipeline(m_pipeline.get()); + commandBuffer->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); + commandBuffer->draw(m_unitAABBVertices.size(), m_instances.size(), 0, 0); + + streaming->multi_deallocate(1, &inputOffset, &totalSize, waitInfo); + + return true; +} + std::array DrawAABB::getVerticesFromAABB(const core::aabbox3d& aabb) { const auto& pMin = aabb.MinEdge; From f18bf3872a5d1b35c1dd84ae2b514c814184bc98 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 7 Jul 2025 11:33:52 +0700 Subject: [PATCH 13/18] moved most core func to CDrawAABB --- 34_DebugDraw/include/CDrawAABB.h | 16 ++-- 34_DebugDraw/main.cpp | 130 ++++--------------------------- 34_DebugDraw/src/CDrawAABB.cpp | 39 ++++++++++ 3 files changed, 63 insertions(+), 122 deletions(-) diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h index 33ff1b1f6..3c8925fbd 100644 --- a/34_DebugDraw/include/CDrawAABB.h +++ b/34_DebugDraw/include/CDrawAABB.h @@ -31,7 +31,8 @@ class DrawAABB final : public core::IReferenceCounted struct SCreationParameters : SCachedCreationParameters { - asset::SPushConstantRange pushConstantRange; + core::smart_refctd_ptr assetManager = nullptr; + system::path localInputCWD; // TODO replace when working from nbl/ext core::smart_refctd_ptr pipelineLayout; core::smart_refctd_ptr renderpass = nullptr; @@ -46,25 +47,30 @@ class DrawAABB final : public core::IReferenceCounted // creates default pipeline layout for push constant version static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange); - static smart_refctd_ptr createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment); + // creates default pipeline layout for streaming version + static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device); + + static core::smart_refctd_ptr createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment); inline const SCachedCreationParameters& getCreationParameters() const { return m_cachedCreationParams; } // records draw command for single AABB, user has to set pipeline outside bool renderSingle(video::IGPUCommandBuffer* commandBuffer); - bool render(video::IGPUCommandBuffer* commandBuffer, ISemaphore::SWaitInfo waitInfo, float* cameraMat3x4); + bool render(video::IGPUCommandBuffer* commandBuffer, video::ISemaphore::SWaitInfo waitInfo, float* cameraMat3x4); static std::array getVerticesFromAABB(const core::aabbox3d& aabb); void addAABB(const core::aabbox3d& aabb, const hlsl::float32_t3& color = { 1,0,0 }); + void clearAABBs(); + protected: - DrawAABB(SCreationParameters&& _params, smart_refctd_ptr pipeline); + DrawAABB(SCreationParameters&& _params, core::smart_refctd_ptr pipeline); ~DrawAABB() override; private: - static smart_refctd_ptr createPipeline(SCreationParameters& params); + static core::smart_refctd_ptr createPipeline(SCreationParameters& params); static bool createStreamingBuffer(SCreationParameters& params); std::vector m_instances; diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index edf849657..40362b1f8 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -123,8 +123,12 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti .size = sizeof(SSimplePushConstants) }; { - ext::drawdebug::DrawAABB::SCreationParameters params; - params.pushConstantRange = simplePcRange; + ext::drawdebug::DrawAABB::SCreationParameters params = {}; + params.assetManager = m_assetMgr; + params.localInputCWD = localInputCWD; + params.pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get()); + params.renderpass = smart_refctd_ptr(renderpass); + params.utilities = m_utils; drawAABB = ext::drawdebug::DrawAABB::create(std::move(params)); } { @@ -140,48 +144,6 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti ).move_into(verticesBuffer); } - // create streaming buffer - // TODO move into CDrawAABB - { - auto RequiredAllocateFlags = core::bitflag(video::IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT); - auto RequiredUsageFlags = core::bitflag(asset::IBuffer::EUF_INDIRECT_BUFFER_BIT) | asset::IBuffer::EUF_VERTEX_BUFFER_BIT | asset::IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; - const uint32_t minStreamingBufferAllocationSize = 128u, maxStreamingBufferAllocationAlignment = 4096u, mdiBufferDefaultSize = /* 2MB */ 1024u * 1024u * 2u; - - auto getRequiredAccessFlags = [&](const bitflag& properties) - { - bitflag flags(IDeviceMemoryAllocation::EMCAF_NO_MAPPING_ACCESS); - - if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_READABLE_BIT)) - flags |= IDeviceMemoryAllocation::EMCAF_READ; - if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_WRITABLE_BIT)) - flags |= IDeviceMemoryAllocation::EMCAF_WRITE; - - return flags; - }; - - IGPUBuffer::SCreationParams mdiCreationParams = {}; - mdiCreationParams.usage = RequiredUsageFlags; - mdiCreationParams.size = mdiBufferDefaultSize; - - auto buffer = m_device->createBuffer(std::move(mdiCreationParams)); - buffer->setObjectDebugName("MDI Upstream Buffer"); - - auto memoryReqs = buffer->getMemoryReqs(); - memoryReqs.memoryTypeBits &= m_device->getPhysicalDevice()->getUpStreamingMemoryTypeBits(); - - auto allocation = m_device->allocate(memoryReqs, buffer.get(), RequiredAllocateFlags); - { - const bool allocated = allocation.isValid(); - assert(allocated); - } - auto memory = allocation.memory; - - if (!memory->map({ 0ull, memoryReqs.size }, getRequiredAccessFlags(memory->getMemoryPropertyFlags()))) - m_logger->log("Could not map device memory!", ILogger::ELL_ERROR); - - streamingBuffer = make_smart_refctd_ptr(SBufferRange{0ull, mdiCreationParams.size, std::move(buffer)}, maxStreamingBufferAllocationAlignment, minStreamingBufferAllocationSize); - } - auto compileShader = [&](const std::string& filePath) -> smart_refctd_ptr { IAssetLoader::SAssetLoadParams lparams = {}; @@ -214,31 +176,6 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti if (!m_pipeline) return logFail("Graphics pipeline creation failed"); } - { - auto vertexShader = compileShader("app_resources/multi_aabb.vertex.hlsl"); - auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); - SPushConstantRange pcRange = { - .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, - .offset = 0, - .size = sizeof(SPushConstants) - }; - - const auto pipelineLayout = m_device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); - - video::IGPUGraphicsPipeline::SCreationParams params[1] = {}; - params[0].layout = pipelineLayout.get(); - params[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; - params[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main" }; - params[0].cached = { - .primitiveAssembly = { - .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, - } - }; - params[0].renderpass = renderpass; - - if (!m_device->createGraphicsPipelines(nullptr, params, &m_streamingPipeline)) - return logFail("Could not create streaming pipeline!"); - } m_window->setCaption("[Nabla Engine] Debug Draw App Test Demo"); m_winMgr->show(m_window.get()); @@ -361,59 +298,18 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti drawAABB->renderSingle(cmdbuf); } - // fill streaming buffer: indirect draw command, then vertex buffer { - auto vertices = ext::drawdebug::DrawAABB::getVerticesFromAABB(testAABB2); - uint32_t instanceCount = 5u; - - using offset_t = streaming_buffer_t::size_type; - constexpr auto MdiSizes = std::to_array({ sizeof(float32_t3), sizeof(InstanceData) }); - // shared nPoT alignment needs to be divisible by all smaller ones to satisfy an allocation from all - constexpr offset_t MaxAlignment = std::reduce(MdiSizes.begin(), MdiSizes.end(), 1, [](const offset_t a, const offset_t b)->offset_t {return std::lcm(a, b); }); - // allocator initialization needs us to round up to PoT - const auto MaxPOTAlignment = roundUpToPoT(MaxAlignment); - - auto* streaming = streamingBuffer.get(); - - auto* const streamingPtr = reinterpret_cast(streaming->getBufferPointer()); - assert(streamingPtr); - - using suballocator_t = core::LinearAddressAllocatorST; - offset_t inputOffset = 0u; - offset_t ImaginarySizeUpperBound = 0x1 << 30; - suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); - uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(sizeof(float32_t3) * vertices.size(), sizeof(float32_t3)); - uint32_t instancesByteOffset = imaginaryChunk.alloc_addr(sizeof(InstanceData) * instanceCount, sizeof(InstanceData)); - const uint32_t totalSize = imaginaryChunk.get_allocated_size(); - - std::chrono::steady_clock::time_point waitTill(std::chrono::years(45)); - streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); - - memcpy(streamingPtr + vertexByteOffset, vertices.data(), sizeof(vertices[0]) * vertices.size()); - auto* instancesIt = reinterpret_cast(streamingPtr + instancesByteOffset); - for (auto i = 0u; i < instanceCount; i++) + const uint32_t aabbCount = 4u; + drawAABB->clearAABBs(); + for (auto i = 0u; i < aabbCount; i++) { - core::matrix3x4SIMD instanceTransform; - instanceTransform.setTranslation(core::vectorSIMDf(i, 0, i, 0)); - instanceTransform.setScale(core::vectorSIMDf(i+1, i+1, i+1)); - memcpy(instancesIt->transform, instanceTransform.pointer(), sizeof(core::matrix3x4SIMD)); - instancesIt->color = float32_t3(i * 0.2, 1, 0); - instancesIt++; + float i2 = (i+1) * 2; + core::aabbox3d aabb = { float(i), 0.f, float(i), i2+i, i2, i2+i}; + drawAABB->addAABB(aabb); } - assert(!streaming->needsManualFlushOrInvalidate()); - - SPushConstants pc; - memcpy(pc.MVP, modelViewProjectionMatrix.pointer(), sizeof(pc.MVP)); - pc.pVertexBuffer = streamingBuffer->getBuffer()->getDeviceAddress() + vertexByteOffset; - pc.pInstanceBuffer = streamingBuffer->getBuffer()->getDeviceAddress() + instancesByteOffset; - - cmdbuf->bindGraphicsPipeline(m_streamingPipeline.get()); - cmdbuf->pushConstants(m_streamingPipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); - cmdbuf->draw(vertices.size(), instanceCount, 0, 0); - const ISemaphore::SWaitInfo drawFinished = { .semaphore = m_semaphore.get(),.value = m_realFrameIx + 1u }; - streaming->multi_deallocate(1, &inputOffset, &totalSize, drawFinished); + drawAABB->render(cmdbuf, drawFinished, modelViewProjectionMatrix.pointer()); } cmdbuf->endRenderPass(); diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp index ae57952ce..defd67bbb 100644 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -49,6 +49,30 @@ DrawAABB::~DrawAABB() smart_refctd_ptr DrawAABB::createPipeline(SCreationParameters& params) { + auto compileShader = [&](const std::string& filePath) -> smart_refctd_ptr + { + IAssetLoader::SAssetLoadParams lparams = {}; + lparams.logger = params.utilities->getLogger(); + lparams.workingDirectory = params.localInputCWD; + auto bundle = params.assetManager->getAsset(filePath, lparams); + if (bundle.getContents().empty() || bundle.getAssetType() != IAsset::ET_SHADER) + { + params.utilities->getLogger()->log("Shader %s not found!", ILogger::ELL_ERROR, filePath.c_str()); + exit(-1); + } + + const auto assets = bundle.getContents(); + assert(assets.size() == 1); + smart_refctd_ptr shaderSrc = IAsset::castDown(assets[0]); + if (!shaderSrc) + return nullptr; + + return params.utilities->getLogicalDevice()->compileShader({ shaderSrc.get() }); + }; + + auto vertexShader = compileShader("app_resources/multi_aabb.vertex.hlsl"); + auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); + video::IGPUGraphicsPipeline::SCreationParams pipelineParams[1] = {}; pipelineParams[0].layout = params.pipelineLayout.get(); pipelineParams[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; @@ -139,6 +163,16 @@ core::smart_refctd_ptr DrawAABB::createDefaultPipelin return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); } +core::smart_refctd_ptr DrawAABB::createDefaultPipelineLayout(video::ILogicalDevice* device) +{ + SPushConstantRange pcRange = { + .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, + .offset = 0, + .size = sizeof(SPushConstants) + }; + return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); +} + smart_refctd_ptr DrawAABB::createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment) { smart_refctd_ptr pipeline; @@ -264,4 +298,9 @@ void DrawAABB::addAABB(const core::aabbox3d& aabb, const hlsl::float32_t3 m_instances.push_back(instance); } +void DrawAABB::clearAABBs() +{ + m_instances.clear(); +} + } From 09ef478a818b4b860be8a2dcfe8192323e3549b5 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 8 Jul 2025 11:55:46 +0700 Subject: [PATCH 14/18] handle streaming buffer overflow --- 34_DebugDraw/app_resources/common.hlsl | 2 +- .../app_resources/multi_aabb.vertex.hlsl | 2 +- 34_DebugDraw/include/CDrawAABB.h | 2 +- 34_DebugDraw/main.cpp | 2 +- 34_DebugDraw/src/CDrawAABB.cpp | 64 +++++++++++-------- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/34_DebugDraw/app_resources/common.hlsl b/34_DebugDraw/app_resources/common.hlsl index b7690b097..6e42628ed 100644 --- a/34_DebugDraw/app_resources/common.hlsl +++ b/34_DebugDraw/app_resources/common.hlsl @@ -10,7 +10,7 @@ struct InstanceData #else float transform[3*4]; #endif - nbl::hlsl::float32_t3 color; + nbl::hlsl::float32_t4 color; }; struct SPushConstants diff --git a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl index 37673deee..ab7a51833 100644 --- a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl +++ b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl @@ -23,7 +23,7 @@ PSInput main() transform[3] = float32_t4(0, 0, 0, 1); float32_t4 position = mul(transform, float32_t4(vertex, 1)); output.position = mul(pc.MVP, position); - output.color = float32_t4(instance.color, 1); + output.color = instance.color; return output; } \ No newline at end of file diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h index 3c8925fbd..d474426f7 100644 --- a/34_DebugDraw/include/CDrawAABB.h +++ b/34_DebugDraw/include/CDrawAABB.h @@ -61,7 +61,7 @@ class DrawAABB final : public core::IReferenceCounted static std::array getVerticesFromAABB(const core::aabbox3d& aabb); - void addAABB(const core::aabbox3d& aabb, const hlsl::float32_t3& color = { 1,0,0 }); + void addAABB(const core::aabbox3d& aabb, const hlsl::float32_t4& color = { 1,0,0,1 }); void clearAABBs(); diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 40362b1f8..bf4decb07 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -305,7 +305,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti { float i2 = (i+1) * 2; core::aabbox3d aabb = { float(i), 0.f, float(i), i2+i, i2, i2+i}; - drawAABB->addAABB(aabb); + drawAABB->addAABB(aabb, {1,0,0,(i+1)*0.2}); } const ISemaphore::SWaitInfo drawFinished = { .semaphore = m_semaphore.get(),.value = m_realFrameIx + 1u }; diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp index defd67bbb..085b0fb9c 100644 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ b/34_DebugDraw/src/CDrawAABB.cpp @@ -215,32 +215,44 @@ bool DrawAABB::render(IGPUCommandBuffer* commandBuffer, ISemaphore::SWaitInfo wa auto* const streamingPtr = reinterpret_cast(streaming->getBufferPointer()); assert(streamingPtr); - using suballocator_t = core::LinearAddressAllocatorST; - offset_t inputOffset = 0u; - offset_t ImaginarySizeUpperBound = 0x1 << 30; - suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); - uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(sizeof(float32_t3) * m_unitAABBVertices.size(), sizeof(float32_t3)); - uint32_t instancesByteOffset = imaginaryChunk.alloc_addr(sizeof(InstanceData) * m_instances.size(), sizeof(InstanceData)); - const uint32_t totalSize = imaginaryChunk.get_allocated_size(); - - std::chrono::steady_clock::time_point waitTill(std::chrono::years(45)); - streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); - - memcpy(streamingPtr + vertexByteOffset, m_unitAABBVertices.data(), sizeof(m_unitAABBVertices[0]) * m_unitAABBVertices.size()); - memcpy(streamingPtr + instancesByteOffset, m_instances.data(), sizeof(m_instances[0]) * m_instances.size()); - - assert(!streaming->needsManualFlushOrInvalidate()); + commandBuffer->bindGraphicsPipeline(m_pipeline.get()); // move outside of loop, only bind once - SPushConstants pc; - memcpy(pc.MVP, cameraMat3x4, sizeof(pc.MVP)); - pc.pVertexBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + vertexByteOffset; - pc.pInstanceBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + instancesByteOffset; - - commandBuffer->bindGraphicsPipeline(m_pipeline.get()); - commandBuffer->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); - commandBuffer->draw(m_unitAABBVertices.size(), m_instances.size(), 0, 0); - - streaming->multi_deallocate(1, &inputOffset, &totalSize, waitInfo); + auto instancesIt = m_instances.begin(); + const uint32_t verticesByteSize = sizeof(float32_t3) * m_unitAABBVertices.size(); + const uint32_t availableInstancesByteSize = streaming->getBuffer()->getSize() - verticesByteSize; + const uint32_t instancesPerIter = availableInstancesByteSize / sizeof(InstanceData); + using suballocator_t = core::LinearAddressAllocatorST; + while (instancesIt != m_instances.end()) + { + const uint32_t instanceCount = min(instancesPerIter, m_instances.size()); + offset_t inputOffset = 0u; + offset_t ImaginarySizeUpperBound = 0x1 << 30; + suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); + uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(verticesByteSize, sizeof(float32_t3)); + uint32_t instancesByteOffset = imaginaryChunk.alloc_addr(sizeof(InstanceData) * instanceCount, sizeof(InstanceData)); + const uint32_t totalSize = imaginaryChunk.get_allocated_size(); + + inputOffset = SCachedCreationParameters::streaming_buffer_t::invalid_value; + std::chrono::steady_clock::time_point waitTill = std::chrono::steady_clock::now() + std::chrono::milliseconds(1u); + streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); + + memcpy(streamingPtr + vertexByteOffset, m_unitAABBVertices.data(), sizeof(m_unitAABBVertices[0]) * m_unitAABBVertices.size()); + memcpy(streamingPtr + instancesByteOffset, std::addressof(*instancesIt), sizeof(InstanceData) * instanceCount); + instancesIt += instanceCount; + + assert(!streaming->needsManualFlushOrInvalidate()); + + SPushConstants pc; + memcpy(pc.MVP, cameraMat3x4, sizeof(pc.MVP)); + pc.pVertexBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + vertexByteOffset; + pc.pInstanceBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + instancesByteOffset; + + commandBuffer->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); + commandBuffer->draw(m_unitAABBVertices.size(), instanceCount, 0, 0); + + streaming->multi_deallocate(1, &inputOffset, &totalSize, waitInfo); + } + // end loop return true; } @@ -284,7 +296,7 @@ std::array DrawAABB::getVerticesFromAABB(const core::aabbox3d& aabb, const hlsl::float32_t3& color) +void DrawAABB::addAABB(const core::aabbox3d& aabb, const hlsl::float32_t4& color) { InstanceData instance; instance.color = color; From aee85b4a4fa51de22ccd640ba3ae338911782429 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 8 Jul 2025 14:00:55 +0700 Subject: [PATCH 15/18] update example scene --- 34_DebugDraw/main.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index bf4decb07..40ccfda9d 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -3,8 +3,8 @@ // For conditions of distribution and use, see copyright notice in nabla.h #include "common.hpp" +#include "nbl/builtin/hlsl/random/xoroshiro.hlsl" #include "app_resources/simple_common.hlsl" -#include "app_resources/common.hlsl" class DebugDrawSampleApp final : public SimpleWindowedApplication, public BuiltinResourcesApplication { @@ -299,13 +299,18 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti } { - const uint32_t aabbCount = 4u; + std::mt19937 gen(42); + std::uniform_real_distribution translate_dis(-50.f, 50.f); + std::uniform_real_distribution scale_dis(1.f, 10.f); + std::uniform_real_distribution color_dis(0.f, 1.f); + const uint32_t aabbCount = 200u; drawAABB->clearAABBs(); for (auto i = 0u; i < aabbCount; i++) { - float i2 = (i+1) * 2; - core::aabbox3d aabb = { float(i), 0.f, float(i), i2+i, i2, i2+i}; - drawAABB->addAABB(aabb, {1,0,0,(i+1)*0.2}); + core::vector3d pmin = { translate_dis(gen), translate_dis(gen), translate_dis(gen) }; + core::vector3d pmax = pmin + core::vector3d{ scale_dis(gen), scale_dis(gen), scale_dis(gen) }; + core::aabbox3d aabb = { pmin, pmax }; + drawAABB->addAABB(aabb, { color_dis(gen),color_dis(gen),color_dis(gen),1}); } const ISemaphore::SWaitInfo drawFinished = { .semaphore = m_semaphore.get(),.value = m_realFrameIx + 1u }; From 738269ede1b9ee83cd5e44f86e290852ce6b0127 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 8 Jul 2025 15:43:36 +0700 Subject: [PATCH 16/18] use debug draw extension --- 34_DebugDraw/CMakeLists.txt | 20 +- 34_DebugDraw/app_resources/common.hlsl | 35 -- .../app_resources/multi_aabb.vertex.hlsl | 29 -- 34_DebugDraw/include/CDrawAABB.h | 85 ----- 34_DebugDraw/include/common.hpp | 3 +- 34_DebugDraw/main.cpp | 16 +- 34_DebugDraw/src/CDrawAABB.cpp | 318 ------------------ 7 files changed, 15 insertions(+), 491 deletions(-) delete mode 100644 34_DebugDraw/app_resources/common.hlsl delete mode 100644 34_DebugDraw/app_resources/multi_aabb.vertex.hlsl delete mode 100644 34_DebugDraw/include/CDrawAABB.h delete mode 100644 34_DebugDraw/src/CDrawAABB.cpp diff --git a/34_DebugDraw/CMakeLists.txt b/34_DebugDraw/CMakeLists.txt index 60c07b1b7..557280430 100644 --- a/34_DebugDraw/CMakeLists.txt +++ b/34_DebugDraw/CMakeLists.txt @@ -1,22 +1,14 @@ -if(NBL_BUILD_IMGUI) - set(NBL_EXTRA_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/src/CDrawAABB.cpp" # TODO remove when moved to nabla - ) - +if(NBL_BUILD_DEBUG_DRAW) set(NBL_INCLUDE_SERACH_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include" ) - # TODO remove - list(APPEND NBL_LIBRARIES - imtestengine - imguizmo - "${NBL_EXT_IMGUI_UI_LIB}" - ) + nbl_create_executable_project("${NBL_EXTRA_SOURCES}" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") - nbl_create_executable_project("${NBL_EXTRA_SOURCES}" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") + add_dependencies(${EXECUTABLE_NAME} ${NBL_EXT_DEBUG_DRAW_TARGET}) + target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${NBL_EXT_DEBUG_DRAW_TARGET}) + target_include_directories(${EXECUTABLE_NAME} PUBLIC $) - # TODO probably remove when moved to nabla if(NBL_EMBED_BUILTIN_RESOURCES) set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData) set(RESOURCE_DIR "app_resources") @@ -34,4 +26,4 @@ if(NBL_BUILD_IMGUI) LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_}) endif() -endif() \ No newline at end of file +endif() diff --git a/34_DebugDraw/app_resources/common.hlsl b/34_DebugDraw/app_resources/common.hlsl deleted file mode 100644 index 6e42628ed..000000000 --- a/34_DebugDraw/app_resources/common.hlsl +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _DRAW_AABB_COMMON_HLSL -#define _DRAW_AABB_COMMON_HLSL - -#include "nbl/builtin/hlsl/cpp_compat.hlsl" - -struct InstanceData -{ -#ifdef __HLSL_VERSION - float32_t3x4 transform; -#else - float transform[3*4]; -#endif - nbl::hlsl::float32_t4 color; -}; - -struct SPushConstants -{ -#ifdef __HLSL_VERSION - float32_t4x4 MVP; -#else - float MVP[4*4]; -#endif - uint64_t pVertexBuffer; - uint64_t pInstanceBuffer; -}; - -#ifdef __HLSL_VERSION -struct PSInput -{ - float32_t4 position : SV_Position; - float32_t4 color : TEXCOORD0; -}; -#endif - -#endif diff --git a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl b/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl deleted file mode 100644 index ab7a51833..000000000 --- a/34_DebugDraw/app_resources/multi_aabb.vertex.hlsl +++ /dev/null @@ -1,29 +0,0 @@ -#pragma shader_stage(vertex) - -#include "nbl/builtin/hlsl/glsl_compat/core.hlsl" -#include "nbl/builtin/hlsl/bda/__ptr.hlsl" -#include "common.hlsl" - -using namespace nbl::hlsl; - -[[vk::push_constant]] SPushConstants pc; - -[shader("vertex")] -PSInput main() -{ - PSInput output; - - float32_t3 vertex = (bda::__ptr::create(pc.pVertexBuffer) + glsl::gl_VertexIndex()).deref_restrict().load(); - InstanceData instance = vk::RawBufferLoad(pc.pInstanceBuffer + sizeof(InstanceData) * glsl::gl_InstanceIndex()); - - float32_t4x4 transform; - transform[0] = instance.transform[0]; - transform[1] = instance.transform[1]; - transform[2] = instance.transform[2]; - transform[3] = float32_t4(0, 0, 0, 1); - float32_t4 position = mul(transform, float32_t4(vertex, 1)); - output.position = mul(pc.MVP, position); - output.color = instance.color; - - return output; -} \ No newline at end of file diff --git a/34_DebugDraw/include/CDrawAABB.h b/34_DebugDraw/include/CDrawAABB.h deleted file mode 100644 index d474426f7..000000000 --- a/34_DebugDraw/include/CDrawAABB.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. -// This file is part of the "Nabla Engine". -// For conditions of distribution and use, see copyright notice in nabla.h - -// TODO move this into nabla - -#ifndef _NBL_EXT_DRAW_AABB_H_ -#define _NBL_EXT_DRAW_AABB_H_ - -#include "nbl/video/declarations.h" -#include "nbl/builtin/hlsl/cpp_compat.hlsl" -#include "../app_resources/common.hlsl" - -namespace nbl::ext::drawdebug -{ -class DrawAABB final : public core::IReferenceCounted -{ -public: - struct SCachedCreationParameters - { - using streaming_buffer_t = video::StreamingTransientDataBufferST>; - - static constexpr inline auto RequiredAllocateFlags = core::bitflag(video::IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT); - static constexpr inline auto RequiredUsageFlags = core::bitflag(asset::IBuffer::EUF_STORAGE_BUFFER_BIT) | asset::IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; - - core::smart_refctd_ptr utilities; - - //! optional, default MDI buffer allocated if not provided - core::smart_refctd_ptr streamingBuffer = nullptr; - }; - - struct SCreationParameters : SCachedCreationParameters - { - core::smart_refctd_ptr assetManager = nullptr; - system::path localInputCWD; // TODO replace when working from nbl/ext - - core::smart_refctd_ptr pipelineLayout; - core::smart_refctd_ptr renderpass = nullptr; - }; - - // creates an instance that draws one AABB via push constant - static core::smart_refctd_ptr create(SCreationParameters&& params); - - // creates an instance that draws multiple AABBs using streaming buffer - // TODO - - // creates default pipeline layout for push constant version - static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange); - - // creates default pipeline layout for streaming version - static core::smart_refctd_ptr createDefaultPipelineLayout(video::ILogicalDevice* device); - - static core::smart_refctd_ptr createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment); - - inline const SCachedCreationParameters& getCreationParameters() const { return m_cachedCreationParams; } - - // records draw command for single AABB, user has to set pipeline outside - bool renderSingle(video::IGPUCommandBuffer* commandBuffer); - - bool render(video::IGPUCommandBuffer* commandBuffer, video::ISemaphore::SWaitInfo waitInfo, float* cameraMat3x4); - - static std::array getVerticesFromAABB(const core::aabbox3d& aabb); - - void addAABB(const core::aabbox3d& aabb, const hlsl::float32_t4& color = { 1,0,0,1 }); - - void clearAABBs(); - -protected: - DrawAABB(SCreationParameters&& _params, core::smart_refctd_ptr pipeline); - ~DrawAABB() override; - -private: - static core::smart_refctd_ptr createPipeline(SCreationParameters& params); - static bool createStreamingBuffer(SCreationParameters& params); - - std::vector m_instances; - std::array m_unitAABBVertices; - - SCachedCreationParameters m_cachedCreationParams; - - core::smart_refctd_ptr m_pipeline; -}; -} - -#endif diff --git a/34_DebugDraw/include/common.hpp b/34_DebugDraw/include/common.hpp index 599c9a2e9..e70eb47a8 100644 --- a/34_DebugDraw/include/common.hpp +++ b/34_DebugDraw/include/common.hpp @@ -8,7 +8,8 @@ #include "nbl/examples/common/CEventCallback.hpp" #include "nbl/examples/examples.hpp" -#include "CDrawAABB.h" +//#include "nbl/CDrawAABB.h" +#include "nbl/ext/DebugDraw/CDrawAABB.h" using namespace nbl; using namespace core; diff --git a/34_DebugDraw/main.cpp b/34_DebugDraw/main.cpp index 40ccfda9d..937d699b8 100644 --- a/34_DebugDraw/main.cpp +++ b/34_DebugDraw/main.cpp @@ -3,7 +3,6 @@ // For conditions of distribution and use, see copyright notice in nabla.h #include "common.hpp" -#include "nbl/builtin/hlsl/random/xoroshiro.hlsl" #include "app_resources/simple_common.hlsl" class DebugDrawSampleApp final : public SimpleWindowedApplication, public BuiltinResourcesApplication @@ -123,16 +122,15 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti .size = sizeof(SSimplePushConstants) }; { - ext::drawdebug::DrawAABB::SCreationParameters params = {}; + ext::debugdraw::DrawAABB::SCreationParameters params = {}; params.assetManager = m_assetMgr; - params.localInputCWD = localInputCWD; - params.pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get()); + params.pipelineLayout = ext::debugdraw::DrawAABB::createDefaultPipelineLayout(m_device.get()); params.renderpass = smart_refctd_ptr(renderpass); params.utilities = m_utils; - drawAABB = ext::drawdebug::DrawAABB::create(std::move(params)); + drawAABB = ext::debugdraw::DrawAABB::create(std::move(params)); } { - auto vertices = ext::drawdebug::DrawAABB::getVerticesFromAABB(testAABB); + auto vertices = ext::debugdraw::DrawAABB::getVerticesFromAABB(testAABB); IGPUBuffer::SCreationParams params; params.size = sizeof(float32_t3) * vertices.size(); params.usage = IGPUBuffer::EUF_STORAGE_BUFFER_BIT | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; @@ -168,11 +166,11 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti auto vertexShader = compileShader("app_resources/simple.vertex.hlsl"); auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); - const auto pipelineLayout = ext::drawdebug::DrawAABB::createDefaultPipelineLayout(m_device.get(), simplePcRange); + const auto pipelineLayout = ext::debugdraw::DrawAABB::createDefaultPipelineLayout(m_device.get(), simplePcRange); IGPUGraphicsPipeline::SShaderSpecInfo vs = { .shader = vertexShader.get(), .entryPoint = "main" }; IGPUGraphicsPipeline::SShaderSpecInfo fs = { .shader = fragmentShader.get(), .entryPoint = "main" }; - m_pipeline = ext::drawdebug::DrawAABB::createDefaultPipeline(m_device.get(), pipelineLayout.get(), renderpass, vs, fs); + m_pipeline = ext::debugdraw::DrawAABB::createDefaultPipeline(m_device.get(), pipelineLayout.get(), renderpass, vs, fs); if (!m_pipeline) return logFail("Graphics pipeline creation failed"); } @@ -455,7 +453,7 @@ class DebugDrawSampleApp final : public SimpleWindowedApplication, public Builti float fov = 60.f, zNear = 0.1f, zFar = 10000.f, moveSpeed = 1.f, rotateSpeed = 1.f; - smart_refctd_ptr drawAABB; + smart_refctd_ptr drawAABB; core::aabbox3d testAABB = core::aabbox3d({ -5, -5, -5 }, { 10, 10, -10 }); core::aabbox3d testAABB2 = core::aabbox3d({ 0, 0, 0 }, { 1, 1, 1 }); smart_refctd_ptr verticesBuffer; diff --git a/34_DebugDraw/src/CDrawAABB.cpp b/34_DebugDraw/src/CDrawAABB.cpp deleted file mode 100644 index 085b0fb9c..000000000 --- a/34_DebugDraw/src/CDrawAABB.cpp +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. -// This file is part of the "Nabla Engine". -// For conditions of distribution and use, see copyright notice in nabla.h - -// TODO move this into nabla - -#include "CDrawAABB.h" - -using namespace nbl; -using namespace core; -using namespace video; -using namespace system; -using namespace asset; -using namespace hlsl; - -namespace nbl::ext::drawdebug -{ - -core::smart_refctd_ptr DrawAABB::create(SCreationParameters&& params) -{ - auto* const logger = params.utilities->getLogger(); - - auto pipeline = createPipeline(params); - if (!pipeline) - { - logger->log("Failed to create pipeline!", ILogger::ELL_ERROR); - return nullptr; - } - - if (!createStreamingBuffer(params)) - { - logger->log("Failed to create streaming buffer!", ILogger::ELL_ERROR); - return nullptr; - } - - return core::smart_refctd_ptr(new DrawAABB(std::move(params), pipeline)); -} - -DrawAABB::DrawAABB(SCreationParameters&& params, smart_refctd_ptr pipeline) - : m_cachedCreationParams(std::move(params)), m_pipeline(pipeline) -{ - const auto unitAABB = core::aabbox3d({ 0, 0, 0 }, { 1, 1, 1 }); - m_unitAABBVertices = getVerticesFromAABB(unitAABB); -} - -DrawAABB::~DrawAABB() -{ -} - -smart_refctd_ptr DrawAABB::createPipeline(SCreationParameters& params) -{ - auto compileShader = [&](const std::string& filePath) -> smart_refctd_ptr - { - IAssetLoader::SAssetLoadParams lparams = {}; - lparams.logger = params.utilities->getLogger(); - lparams.workingDirectory = params.localInputCWD; - auto bundle = params.assetManager->getAsset(filePath, lparams); - if (bundle.getContents().empty() || bundle.getAssetType() != IAsset::ET_SHADER) - { - params.utilities->getLogger()->log("Shader %s not found!", ILogger::ELL_ERROR, filePath.c_str()); - exit(-1); - } - - const auto assets = bundle.getContents(); - assert(assets.size() == 1); - smart_refctd_ptr shaderSrc = IAsset::castDown(assets[0]); - if (!shaderSrc) - return nullptr; - - return params.utilities->getLogicalDevice()->compileShader({ shaderSrc.get() }); - }; - - auto vertexShader = compileShader("app_resources/multi_aabb.vertex.hlsl"); - auto fragmentShader = compileShader("app_resources/simple.fragment.hlsl"); - - video::IGPUGraphicsPipeline::SCreationParams pipelineParams[1] = {}; - pipelineParams[0].layout = params.pipelineLayout.get(); - pipelineParams[0].vertexShader = { .shader = vertexShader.get(), .entryPoint = "main" }; - pipelineParams[0].fragmentShader = { .shader = fragmentShader.get(), .entryPoint = "main" }; - pipelineParams[0].cached = { - .primitiveAssembly = { - .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, - } - }; - pipelineParams[0].renderpass = params.renderpass.get(); - - smart_refctd_ptr pipeline; - params.utilities->getLogicalDevice()->createGraphicsPipelines(nullptr, pipelineParams, &pipeline); - if (!pipeline) - { - params.utilities->getLogger()->log("Could not create streaming pipeline!", ILogger::ELL_ERROR); - return nullptr; - } - - return pipeline; -} - -bool DrawAABB::createStreamingBuffer(SCreationParameters& params) -{ - const uint32_t minStreamingBufferAllocationSize = 128u, maxStreamingBufferAllocationAlignment = 4096u, mdiBufferDefaultSize = /* 2MB */ 1024u * 1024u * 2u; - - auto getRequiredAccessFlags = [&](const bitflag& properties) - { - bitflag flags(IDeviceMemoryAllocation::EMCAF_NO_MAPPING_ACCESS); - - if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_READABLE_BIT)) - flags |= IDeviceMemoryAllocation::EMCAF_READ; - if (properties.hasFlags(IDeviceMemoryAllocation::EMPF_HOST_WRITABLE_BIT)) - flags |= IDeviceMemoryAllocation::EMCAF_WRITE; - - return flags; - }; - - if (!params.streamingBuffer) - { - IGPUBuffer::SCreationParams mdiCreationParams = {}; - mdiCreationParams.usage = SCachedCreationParameters::RequiredUsageFlags; - mdiCreationParams.size = mdiBufferDefaultSize; - - auto buffer = params.utilities->getLogicalDevice()->createBuffer(std::move(mdiCreationParams)); - buffer->setObjectDebugName("AABB Streaming Buffer"); - - auto memoryReqs = buffer->getMemoryReqs(); - memoryReqs.memoryTypeBits &= params.utilities->getLogicalDevice()->getPhysicalDevice()->getUpStreamingMemoryTypeBits(); - - auto allocation = params.utilities->getLogicalDevice()->allocate(memoryReqs, buffer.get(), SCachedCreationParameters::RequiredAllocateFlags); - { - const bool allocated = allocation.isValid(); - assert(allocated); - } - auto memory = allocation.memory; - - if (!memory->map({ 0ull, memoryReqs.size }, getRequiredAccessFlags(memory->getMemoryPropertyFlags()))) - params.utilities->getLogger()->log("Could not map device memory!", ILogger::ELL_ERROR); - - params.streamingBuffer = make_smart_refctd_ptr(SBufferRange{0ull, mdiCreationParams.size, std::move(buffer)}, maxStreamingBufferAllocationAlignment, minStreamingBufferAllocationSize); - } - - auto buffer = params.streamingBuffer->getBuffer(); - auto binding = buffer->getBoundMemory(); - - const auto validation = std::to_array - ({ - std::make_pair(buffer->getCreationParams().usage.hasFlags(SCachedCreationParameters::RequiredUsageFlags), "Streaming buffer must be created with IBuffer::EUF_STORAGE_BUFFER_BIT | IBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT enabled!"), - std::make_pair(bool(buffer->getMemoryReqs().memoryTypeBits & params.utilities->getLogicalDevice()->getPhysicalDevice()->getUpStreamingMemoryTypeBits()), "Streaming buffer must have up-streaming memory type bits enabled!"), - std::make_pair(binding.memory->getAllocateFlags().hasFlags(SCachedCreationParameters::RequiredAllocateFlags), "Streaming buffer's memory must be allocated with IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT enabled!"), - std::make_pair(binding.memory->isCurrentlyMapped(), "Streaming buffer's memory must be mapped!"), // streaming buffer contructor already validates it, but cannot assume user won't unmap its own buffer for some reason (sorry if you have just hit it) - std::make_pair(binding.memory->getCurrentMappingAccess().hasFlags(getRequiredAccessFlags(binding.memory->getMemoryPropertyFlags())), "Streaming buffer's memory current mapping access flags don't meet requirements!") - }); - - for (const auto& [ok, error] : validation) - if (!ok) - { - params.utilities->getLogger()->log(error, ILogger::ELL_ERROR); - return false; - } - - return true; -} - -core::smart_refctd_ptr DrawAABB::createDefaultPipelineLayout(video::ILogicalDevice* device, const asset::SPushConstantRange& pcRange) -{ - return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); -} - -core::smart_refctd_ptr DrawAABB::createDefaultPipelineLayout(video::ILogicalDevice* device) -{ - SPushConstantRange pcRange = { - .stageFlags = IShader::E_SHADER_STAGE::ESS_VERTEX, - .offset = 0, - .size = sizeof(SPushConstants) - }; - return device->createPipelineLayout({ &pcRange , 1 }, nullptr, nullptr, nullptr, nullptr); -} - -smart_refctd_ptr DrawAABB::createDefaultPipeline(video::ILogicalDevice* device, video::IGPUPipelineLayout* layout, video::IGPURenderpass* renderpass, video::IGPUGraphicsPipeline::SShaderSpecInfo& vertex, video::IGPUGraphicsPipeline::SShaderSpecInfo& fragment) -{ - smart_refctd_ptr pipeline; - - video::IGPUGraphicsPipeline::SCreationParams params[1] = {}; - params[0].layout = layout; - params[0].vertexShader = vertex; - params[0].fragmentShader = fragment; - params[0].cached = { - .primitiveAssembly = { - .primitiveType = asset::E_PRIMITIVE_TOPOLOGY::EPT_LINE_LIST, - } - }; - params[0].renderpass = renderpass; - - device->createGraphicsPipelines(nullptr, params, &pipeline); - - return pipeline; -} - -bool DrawAABB::renderSingle(IGPUCommandBuffer* commandBuffer) -{ - commandBuffer->setLineWidth(1.f); - commandBuffer->draw(24, 1, 0, 0); - - return true; -} - -bool DrawAABB::render(IGPUCommandBuffer* commandBuffer, ISemaphore::SWaitInfo waitInfo, float* cameraMat3x4) -{ - using offset_t = SCachedCreationParameters::streaming_buffer_t::size_type; - constexpr auto MdiSizes = std::to_array({ sizeof(float32_t3), sizeof(InstanceData) }); - // shared nPoT alignment needs to be divisible by all smaller ones to satisfy an allocation from all - constexpr offset_t MaxAlignment = std::reduce(MdiSizes.begin(), MdiSizes.end(), 1, [](const offset_t a, const offset_t b)->offset_t {return std::lcm(a, b); }); - // allocator initialization needs us to round up to PoT - const auto MaxPOTAlignment = roundUpToPoT(MaxAlignment); - - auto* streaming = m_cachedCreationParams.streamingBuffer.get(); - - auto* const streamingPtr = reinterpret_cast(streaming->getBufferPointer()); - assert(streamingPtr); - - commandBuffer->bindGraphicsPipeline(m_pipeline.get()); // move outside of loop, only bind once - - auto instancesIt = m_instances.begin(); - const uint32_t verticesByteSize = sizeof(float32_t3) * m_unitAABBVertices.size(); - const uint32_t availableInstancesByteSize = streaming->getBuffer()->getSize() - verticesByteSize; - const uint32_t instancesPerIter = availableInstancesByteSize / sizeof(InstanceData); - using suballocator_t = core::LinearAddressAllocatorST; - while (instancesIt != m_instances.end()) - { - const uint32_t instanceCount = min(instancesPerIter, m_instances.size()); - offset_t inputOffset = 0u; - offset_t ImaginarySizeUpperBound = 0x1 << 30; - suballocator_t imaginaryChunk(nullptr, inputOffset, 0, roundUpToPoT(MaxAlignment), ImaginarySizeUpperBound); - uint32_t vertexByteOffset = imaginaryChunk.alloc_addr(verticesByteSize, sizeof(float32_t3)); - uint32_t instancesByteOffset = imaginaryChunk.alloc_addr(sizeof(InstanceData) * instanceCount, sizeof(InstanceData)); - const uint32_t totalSize = imaginaryChunk.get_allocated_size(); - - inputOffset = SCachedCreationParameters::streaming_buffer_t::invalid_value; - std::chrono::steady_clock::time_point waitTill = std::chrono::steady_clock::now() + std::chrono::milliseconds(1u); - streaming->multi_allocate(waitTill, 1, &inputOffset, &totalSize, &MaxAlignment); - - memcpy(streamingPtr + vertexByteOffset, m_unitAABBVertices.data(), sizeof(m_unitAABBVertices[0]) * m_unitAABBVertices.size()); - memcpy(streamingPtr + instancesByteOffset, std::addressof(*instancesIt), sizeof(InstanceData) * instanceCount); - instancesIt += instanceCount; - - assert(!streaming->needsManualFlushOrInvalidate()); - - SPushConstants pc; - memcpy(pc.MVP, cameraMat3x4, sizeof(pc.MVP)); - pc.pVertexBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + vertexByteOffset; - pc.pInstanceBuffer = m_cachedCreationParams.streamingBuffer->getBuffer()->getDeviceAddress() + instancesByteOffset; - - commandBuffer->pushConstants(m_pipeline->getLayout(), ESS_VERTEX, 0, sizeof(SPushConstants), &pc); - commandBuffer->draw(m_unitAABBVertices.size(), instanceCount, 0, 0); - - streaming->multi_deallocate(1, &inputOffset, &totalSize, waitInfo); - } - // end loop - - return true; -} - -std::array DrawAABB::getVerticesFromAABB(const core::aabbox3d& aabb) -{ - const auto& pMin = aabb.MinEdge; - const auto& pMax = aabb.MaxEdge; - - std::array vertices; - vertices[0] = float32_t3(pMin.X, pMin.Y, pMin.Z); - vertices[1] = float32_t3(pMax.X, pMin.Y, pMin.Z); - vertices[2] = float32_t3(pMin.X, pMin.Y, pMin.Z); - vertices[3] = float32_t3(pMin.X, pMin.Y, pMax.Z); - - vertices[4] = float32_t3(pMax.X, pMin.Y, pMax.Z); - vertices[5] = float32_t3(pMax.X, pMin.Y, pMin.Z); - vertices[6] = float32_t3(pMax.X, pMin.Y, pMax.Z); - vertices[7] = float32_t3(pMin.X, pMin.Y, pMax.Z); - - vertices[8] = float32_t3(pMin.X, pMax.Y, pMin.Z); - vertices[9] = float32_t3(pMax.X, pMax.Y, pMin.Z); - vertices[10] = float32_t3(pMin.X, pMax.Y, pMin.Z); - vertices[11] = float32_t3(pMin.X, pMax.Y, pMax.Z); - - vertices[12] = float32_t3(pMax.X, pMax.Y, pMax.Z); - vertices[13] = float32_t3(pMax.X, pMax.Y, pMin.Z); - vertices[14] = float32_t3(pMax.X, pMax.Y, pMax.Z); - vertices[15] = float32_t3(pMin.X, pMax.Y, pMax.Z); - - vertices[16] = float32_t3(pMin.X, pMin.Y, pMin.Z); - vertices[17] = float32_t3(pMin.X, pMax.Y, pMin.Z); - vertices[18] = float32_t3(pMax.X, pMin.Y, pMin.Z); - vertices[19] = float32_t3(pMax.X, pMax.Y, pMin.Z); - - vertices[20] = float32_t3(pMin.X, pMin.Y, pMax.Z); - vertices[21] = float32_t3(pMin.X, pMax.Y, pMax.Z); - vertices[22] = float32_t3(pMax.X, pMin.Y, pMax.Z); - vertices[23] = float32_t3(pMax.X, pMax.Y, pMax.Z); - - return vertices; -} - -void DrawAABB::addAABB(const core::aabbox3d& aabb, const hlsl::float32_t4& color) -{ - InstanceData instance; - instance.color = color; - - core::matrix3x4SIMD instanceTransform; - instanceTransform.setTranslation(core::vectorSIMDf(aabb.MinEdge.X, aabb.MinEdge.Y, aabb.MinEdge.Z, 0)); - const auto diagonal = aabb.MaxEdge - aabb.MinEdge; - instanceTransform.setScale(core::vectorSIMDf(diagonal.X, diagonal.Y, diagonal.Z)); - memcpy(instance.transform, instanceTransform.pointer(), sizeof(core::matrix3x4SIMD)); - - m_instances.push_back(instance); -} - -void DrawAABB::clearAABBs() -{ - m_instances.clear(); -} - -} From 61b1c0085ecb5add2b06a71c705b6a91143fcbb3 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 8 Jul 2025 17:16:37 +0700 Subject: [PATCH 17/18] removed old mesh loaders --- 29_MeshLoaders/CMakeLists.txt | 37 - 29_MeshLoaders/config.json.template | 28 - 29_MeshLoaders/main.cpp | 1404 --------------------------- 29_MeshLoaders/pipeline.groovy | 50 - 4 files changed, 1519 deletions(-) delete mode 100644 29_MeshLoaders/CMakeLists.txt delete mode 100644 29_MeshLoaders/config.json.template delete mode 100644 29_MeshLoaders/main.cpp delete mode 100644 29_MeshLoaders/pipeline.groovy diff --git a/29_MeshLoaders/CMakeLists.txt b/29_MeshLoaders/CMakeLists.txt deleted file mode 100644 index 07b0fd396..000000000 --- a/29_MeshLoaders/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -include(common RESULT_VARIABLE RES) -if(NOT RES) - message(FATAL_ERROR "common.cmake not found. Should be in {repo_root}/cmake directory") -endif() - -if(NBL_BUILD_IMGUI) - set(NBL_INCLUDE_SERACH_DIRECTORIES - "${CMAKE_CURRENT_SOURCE_DIR}/include" - ) - - list(APPEND NBL_LIBRARIES - imtestengine - "${NBL_EXT_IMGUI_UI_LIB}" - ) - - nbl_create_executable_project("" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") - - if(NBL_EMBED_BUILTIN_RESOURCES) - set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData) - set(RESOURCE_DIR "app_resources") - - get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE) - get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE) - - file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*") - foreach(RES_FILE ${BUILTIN_RESOURCE_FILES}) - LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}") - endforeach() - - ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}") - - LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_}) - endif() -endif() - - diff --git a/29_MeshLoaders/config.json.template b/29_MeshLoaders/config.json.template deleted file mode 100644 index 2c42b001d..000000000 --- a/29_MeshLoaders/config.json.template +++ /dev/null @@ -1,28 +0,0 @@ -{ - "enableParallelBuild": true, - "threadsPerBuildProcess" : 2, - "isExecuted": false, - "scriptPath": "", - "cmake": { - "configurations": [ "Release", "Debug", "RelWithDebInfo" ], - "buildModes": [], - "requiredOptions": [ "NBL_BUILD_MITSUBA_LOADER" ] - }, - "profiles": [ - { - "backend": "vulkan", - "platform": "windows", - "buildModes": [], - "runConfiguration": "Release", - "gpuArchitectures": [] - } - ], - "dependencies": [], - "data": [ - { - "dependencies": [], - "command": [""], - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/29_MeshLoaders/main.cpp b/29_MeshLoaders/main.cpp deleted file mode 100644 index 6afb74a5c..000000000 --- a/29_MeshLoaders/main.cpp +++ /dev/null @@ -1,1404 +0,0 @@ -// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O. -// This file is part of the "Nabla Engine". -// For conditions of distribution and use, see copyright notice in nabla.h - -#include -#include "nbl/asset/utils/CGeometryCreator.h" -#include "nbl/application_templates/MonoAssetManagerAndBuiltinResourceApplication.hpp" - -#include -#include - -using namespace nbl; -using namespace core; -using namespace hlsl; -using namespace system; -using namespace asset; -using namespace ui; -using namespace video; - - -class MeshLoadersApp final : public examples::SimpleWindowedApplication, public application_templates::MonoAssetManagerAndBuiltinResourceApplication -{ - using device_base_t = examples::SimpleWindowedApplication; - using asset_base_t = application_templates::MonoAssetManagerAndBuiltinResourceApplication; - - constexpr static inline uint32_t WIN_W = 1280, WIN_H = 720; - constexpr static inline uint32_t MaxFramesInFlight = 3u; - constexpr static inline uint8_t MaxUITextureCount = 1u; - - - public: - inline MeshLoadersApp(const path& _localInputCWD, const path& _localOutputCWD, const path& _sharedInputCWD, const path& _sharedOutputCWD) - : IApplicationFramework(_localInputCWD, _localOutputCWD, _sharedInputCWD, _sharedOutputCWD) - { - } - - inline SPhysicalDeviceFeatures getPreferredDeviceFeatures() const override - { - auto retval = device_base_t::getPreferredDeviceFeatures(); - retval.accelerationStructure = true; - retval.rayQuery = true; - return retval; - } - - inline core::vector getSurfaces() const override - { - if (!m_surface) - { - { - auto windowCallback = core::make_smart_refctd_ptr(smart_refctd_ptr(m_inputSystem), smart_refctd_ptr(m_logger)); - IWindow::SCreationParams params = {}; - params.callback = core::make_smart_refctd_ptr(); - params.width = WIN_W; - params.height = WIN_H; - params.x = 32; - params.y = 32; - params.flags = ui::IWindow::ECF_HIDDEN | IWindow::ECF_BORDERLESS | IWindow::ECF_RESIZABLE; - params.windowCaption = "MeshLoadersApp"; - params.callback = windowCallback; - const_cast&>(m_window) = m_winMgr->createWindow(std::move(params)); - } - - auto surface = CSurfaceVulkanWin32::create(smart_refctd_ptr(m_api), smart_refctd_ptr_static_cast(m_window)); - const_cast&>(m_surface) = CSimpleResizeSurface::create(std::move(surface)); - } - - if (m_surface) - return { {m_surface->getSurface()/*,EQF_NONE*/} }; - - return {}; - } - - // so that we can use the same queue for asset converter and rendering - inline core::vector getQueueRequirements() const override - { - auto reqs = device_base_t::getQueueRequirements(); - reqs.front().requiredFlags |= IQueue::FAMILY_FLAGS::TRANSFER_BIT; - reqs.front().requiredFlags |= IQueue::FAMILY_FLAGS::COMPUTE_BIT; - return reqs; - } - - inline bool onAppInitialized(smart_refctd_ptr&& system) override - { - m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); - - if (!device_base_t::onAppInitialized(smart_refctd_ptr(system))) - return false; - - if (!asset_base_t::onAppInitialized(smart_refctd_ptr(system))) - return false; - -#if 0 - // Load Custom Shader - auto loadCompileAndCreateShader = [&](const std::string& relPath) -> smart_refctd_ptr - { - IAssetLoader::SAssetLoadParams lp = {}; - lp.logger = m_logger.get(); - lp.workingDirectory = ""; // virtual root - auto assetBundle = m_assetMgr->getAsset(relPath, lp); - const auto assets = assetBundle.getContents(); - if (assets.empty()) - return nullptr; - - // lets go straight from ICPUSpecializedShader to IGPUSpecializedShader - auto sourceRaw = IAsset::castDown(assets[0]); - if (!sourceRaw) - return nullptr; - - return m_device->createShader({ sourceRaw.get(), nullptr, shaderReadCache.get(), shaderWriteCache.get() }); - }; - - // load shaders - const auto raygenShader = loadCompileAndCreateShader("app_resources/raytrace.rgen.hlsl"); - const auto closestHitShader = loadCompileAndCreateShader("app_resources/raytrace.rchit.hlsl"); - const auto proceduralClosestHitShader = loadCompileAndCreateShader("app_resources/raytrace_procedural.rchit.hlsl"); - const auto intersectionHitShader = loadCompileAndCreateShader("app_resources/raytrace.rint.hlsl"); - const auto anyHitShaderColorPayload = loadCompileAndCreateShader("app_resources/raytrace.rahit.hlsl"); - const auto anyHitShaderShadowPayload = loadCompileAndCreateShader("app_resources/raytrace_shadow.rahit.hlsl"); - const auto missShader = loadCompileAndCreateShader("app_resources/raytrace.rmiss.hlsl"); - const auto missShadowShader = loadCompileAndCreateShader("app_resources/raytrace_shadow.rmiss.hlsl"); - const auto directionalLightCallShader = loadCompileAndCreateShader("app_resources/light_directional.rcall.hlsl"); - const auto pointLightCallShader = loadCompileAndCreateShader("app_resources/light_point.rcall.hlsl"); - const auto spotLightCallShader = loadCompileAndCreateShader("app_resources/light_spot.rcall.hlsl"); - const auto fragmentShader = loadCompileAndCreateShader("app_resources/present.frag.hlsl"); -#endif - - m_semaphore = m_device->createSemaphore(m_realFrameIx); - if (!m_semaphore) - return logFail("Failed to Create a Semaphore!"); - - auto gQueue = getGraphicsQueue(); - - // Create renderpass and init surface - nbl::video::IGPURenderpass* renderpass; - { - ISwapchain::SCreationParams swapchainParams = { .surface = smart_refctd_ptr(m_surface->getSurface()) }; - if (!swapchainParams.deduceFormat(m_physicalDevice)) - return logFail("Could not choose a Surface Format for the Swapchain!"); - - const static IGPURenderpass::SCreationParams::SSubpassDependency dependencies[] = - { - { - .srcSubpass = IGPURenderpass::SCreationParams::SSubpassDependency::External, - .dstSubpass = 0, - .memoryBarrier = - { - .srcStageMask = asset::PIPELINE_STAGE_FLAGS::COPY_BIT, - .srcAccessMask = asset::ACCESS_FLAGS::TRANSFER_WRITE_BIT, - .dstStageMask = asset::PIPELINE_STAGE_FLAGS::COLOR_ATTACHMENT_OUTPUT_BIT, - .dstAccessMask = asset::ACCESS_FLAGS::COLOR_ATTACHMENT_WRITE_BIT - } - }, - { - .srcSubpass = 0, - .dstSubpass = IGPURenderpass::SCreationParams::SSubpassDependency::External, - .memoryBarrier = - { - .srcStageMask = asset::PIPELINE_STAGE_FLAGS::COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = asset::ACCESS_FLAGS::COLOR_ATTACHMENT_WRITE_BIT - } - }, - IGPURenderpass::SCreationParams::DependenciesEnd - }; - - auto scResources = std::make_unique(m_device.get(), swapchainParams.surfaceFormat.format, dependencies); - renderpass = scResources->getRenderpass(); - - if (!renderpass) - return logFail("Failed to create Renderpass!"); - - if (!m_surface || !m_surface->init(gQueue, std::move(scResources), swapchainParams.sharedParams)) - return logFail("Could not create Window & Surface or initialize the Surface!"); - } -#if 0 - auto pool = m_device->createCommandPool(gQueue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); - - m_converter = CAssetConverter::create({ .device = m_device.get(), .optimizer = {} }); - - for (auto i = 0u; i < MaxFramesInFlight; i++) - { - if (!pool) - return logFail("Couldn't create Command Pool!"); - if (!pool->createCommandBuffers(IGPUCommandPool::BUFFER_LEVEL::PRIMARY, { m_cmdBufs.data() + i, 1 })) - return logFail("Couldn't create Command Buffer!"); - } -#endif - m_winMgr->setWindowSize(m_window.get(), WIN_W, WIN_H); - m_surface->recreateSwapchain(); - -#if 0 - // create output images - m_hdrImage = m_device->createImage({ - { - .type = IGPUImage::ET_2D, - .samples = ICPUImage::ESCF_1_BIT, - .format = EF_R16G16B16A16_SFLOAT, - .extent = {WIN_W, WIN_H, 1}, - .mipLevels = 1, - .arrayLayers = 1, - .flags = IImage::ECF_NONE, - .usage = bitflag(IImage::EUF_STORAGE_BIT) | IImage::EUF_TRANSFER_SRC_BIT | IImage::EUF_SAMPLED_BIT - } - }); - - if (!m_hdrImage || !m_device->allocate(m_hdrImage->getMemoryReqs(), m_hdrImage.get()).isValid()) - return logFail("Could not create HDR Image"); - - m_hdrImageView = m_device->createImageView({ - .flags = IGPUImageView::ECF_NONE, - .subUsages = IGPUImage::E_USAGE_FLAGS::EUF_STORAGE_BIT | IGPUImage::E_USAGE_FLAGS::EUF_SAMPLED_BIT, - .image = m_hdrImage, - .viewType = IGPUImageView::E_TYPE::ET_2D, - .format = asset::EF_R16G16B16A16_SFLOAT - }); - - - - // ray trace pipeline and descriptor set layout setup - { - const IGPUDescriptorSetLayout::SBinding bindings[] = { - { - .binding = 0, - .type = asset::IDescriptor::E_TYPE::ET_ACCELERATION_STRUCTURE, - .createFlags = IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE, - .stageFlags = asset::IShader::E_SHADER_STAGE::ESS_RAYGEN, - .count = 1, - }, - { - .binding = 1, - .type = asset::IDescriptor::E_TYPE::ET_STORAGE_IMAGE, - .createFlags = IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE, - .stageFlags = asset::IShader::E_SHADER_STAGE::ESS_RAYGEN, - .count = 1, - } - }; - const auto descriptorSetLayout = m_device->createDescriptorSetLayout(bindings); - - const std::array dsLayoutPtrs = { descriptorSetLayout.get() }; - m_rayTracingDsPool = m_device->createDescriptorPoolForDSLayouts(IDescriptorPool::ECF_UPDATE_AFTER_BIND_BIT, std::span(dsLayoutPtrs.begin(), dsLayoutPtrs.end())); - m_rayTracingDs = m_rayTracingDsPool->createDescriptorSet(descriptorSetLayout); - - const SPushConstantRange pcRange = { - .stageFlags = IShader::E_SHADER_STAGE::ESS_ALL_RAY_TRACING, - .offset = 0u, - .size = sizeof(SPushConstants), - }; - const auto pipelineLayout = m_device->createPipelineLayout({ &pcRange, 1 }, smart_refctd_ptr(descriptorSetLayout), nullptr, nullptr, nullptr); - - IGPURayTracingPipeline::SCreationParams params = {}; - - enum RtDemoShader - { - RTDS_RAYGEN, - RTDS_MISS, - RTDS_MISS_SHADOW, - RTDS_CLOSEST_HIT, - RTDS_SPHERE_CLOSEST_HIT, - RTDS_ANYHIT_PRIMARY, - RTDS_ANYHIT_SHADOW, - RTDS_INTERSECTION, - RTDS_DIRECTIONAL_CALL, - RTDS_POINT_CALL, - RTDS_SPOT_CALL, - RTDS_COUNT - }; - - IGPUShader::SSpecInfo shaders[RTDS_COUNT]; - shaders[RTDS_RAYGEN] = { .shader = raygenShader.get() }; - shaders[RTDS_MISS] = { .shader = missShader.get() }; - shaders[RTDS_MISS_SHADOW] = { .shader = missShadowShader.get() }; - shaders[RTDS_CLOSEST_HIT] = { .shader = closestHitShader.get() }; - shaders[RTDS_SPHERE_CLOSEST_HIT] = { .shader = proceduralClosestHitShader.get() }; - shaders[RTDS_ANYHIT_PRIMARY] = { .shader = anyHitShaderColorPayload.get() }; - shaders[RTDS_ANYHIT_SHADOW] = { .shader = anyHitShaderShadowPayload.get() }; - shaders[RTDS_INTERSECTION] = { .shader = intersectionHitShader.get() }; - shaders[RTDS_DIRECTIONAL_CALL] = { .shader = directionalLightCallShader.get() }; - shaders[RTDS_POINT_CALL] = { .shader = pointLightCallShader.get() }; - shaders[RTDS_SPOT_CALL] = { .shader = spotLightCallShader.get() }; - - params.layout = pipelineLayout.get(); - params.shaders = std::span(shaders); - using RayTracingFlags = IGPURayTracingPipeline::SCreationParams::FLAGS; - params.flags = core::bitflag(RayTracingFlags::NO_NULL_MISS_SHADERS) | - RayTracingFlags::NO_NULL_INTERSECTION_SHADERS | - RayTracingFlags::NO_NULL_ANY_HIT_SHADERS; - - auto& shaderGroups = params.shaderGroups; - - shaderGroups.raygen = { .index = RTDS_RAYGEN }; - - IRayTracingPipelineBase::SGeneralShaderGroup missGroups[EMT_COUNT]; - missGroups[EMT_PRIMARY] = { .index = RTDS_MISS }; - missGroups[EMT_OCCLUSION] = { .index = RTDS_MISS_SHADOW }; - shaderGroups.misses = missGroups; - - auto getHitGroupIndex = [](E_GEOM_TYPE geomType, E_RAY_TYPE rayType) - { - return geomType * ERT_COUNT + rayType; - }; - IRayTracingPipelineBase::SHitShaderGroup hitGroups[E_RAY_TYPE::ERT_COUNT * E_GEOM_TYPE::EGT_COUNT]; - hitGroups[getHitGroupIndex(EGT_TRIANGLES, ERT_PRIMARY)] = { - .closestHit = RTDS_CLOSEST_HIT, - .anyHit = RTDS_ANYHIT_PRIMARY, - }; - hitGroups[getHitGroupIndex(EGT_TRIANGLES, ERT_OCCLUSION)] = { - .closestHit = IGPURayTracingPipeline::SGeneralShaderGroup::Unused, - .anyHit = RTDS_ANYHIT_SHADOW, - }; - hitGroups[getHitGroupIndex(EGT_PROCEDURAL, ERT_PRIMARY)] = { - .closestHit = RTDS_SPHERE_CLOSEST_HIT, - .anyHit = RTDS_ANYHIT_PRIMARY, - .intersection = RTDS_INTERSECTION, - }; - hitGroups[getHitGroupIndex(EGT_PROCEDURAL, ERT_OCCLUSION)] = { - .closestHit = IGPURayTracingPipeline::SGeneralShaderGroup::Unused, - .anyHit = RTDS_ANYHIT_SHADOW, - .intersection = RTDS_INTERSECTION, - }; - shaderGroups.hits = hitGroups; - - IRayTracingPipelineBase::SGeneralShaderGroup callableGroups[ELT_COUNT]; - callableGroups[ELT_DIRECTIONAL] = { .index = RTDS_DIRECTIONAL_CALL }; - callableGroups[ELT_POINT] = { .index = RTDS_POINT_CALL }; - callableGroups[ELT_SPOT] = { .index = RTDS_SPOT_CALL }; - shaderGroups.callables = callableGroups; - - params.cached.maxRecursionDepth = 1; - params.cached.dynamicStackSize = true; - - if (!m_device->createRayTracingPipelines(nullptr, { ¶ms, 1 }, &m_rayTracingPipeline)) - return logFail("Failed to create ray tracing pipeline"); - - calculateRayTracingStackSize(m_rayTracingPipeline); - - if (!createShaderBindingTable(m_rayTracingPipeline)) - return logFail("Could not create shader binding table"); - - } - - auto assetManager = make_smart_refctd_ptr(smart_refctd_ptr(system)); - auto* geometryCreator = assetManager->getGeometryCreator(); - - if (!createIndirectBuffer()) - return logFail("Could not create indirect buffer"); - - if (!createAccelerationStructuresFromGeometry(geometryCreator)) - return logFail("Could not create acceleration structures from geometry creator"); - - ISampler::SParams samplerParams = { - .AnisotropicFilter = 0 - }; - auto defaultSampler = m_device->createSampler(samplerParams); - - { - const IGPUDescriptorSetLayout::SBinding bindings[] = { - { - .binding = 0u, - .type = nbl::asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER, - .createFlags = ICPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE, - .stageFlags = IShader::E_SHADER_STAGE::ESS_FRAGMENT, - .count = 1u, - .immutableSamplers = &defaultSampler - } - }; - auto gpuPresentDescriptorSetLayout = m_device->createDescriptorSetLayout(bindings); - const video::IGPUDescriptorSetLayout* const layouts[] = { gpuPresentDescriptorSetLayout.get() }; - const uint32_t setCounts[] = { 1u }; - m_presentDsPool = m_device->createDescriptorPoolForDSLayouts(IDescriptorPool::E_CREATE_FLAGS::ECF_NONE, layouts, setCounts); - m_presentDs = m_presentDsPool->createDescriptorSet(gpuPresentDescriptorSetLayout); - - auto scRes = static_cast(m_surface->getSwapchainResources()); - ext::FullScreenTriangle::ProtoPipeline fsTriProtoPPln(m_assetMgr.get(), m_device.get(), m_logger.get()); - if (!fsTriProtoPPln) - return logFail("Failed to create Full Screen Triangle protopipeline or load its vertex shader!"); - - const IGPUShader::SSpecInfo fragSpec = { - .entryPoint = "main", - .shader = fragmentShader.get() - }; - - auto presentLayout = m_device->createPipelineLayout( - {}, - core::smart_refctd_ptr(gpuPresentDescriptorSetLayout), - nullptr, - nullptr, - nullptr - ); - m_presentPipeline = fsTriProtoPPln.createPipeline(fragSpec, presentLayout.get(), scRes->getRenderpass()); - if (!m_presentPipeline) - return logFail("Could not create Graphics Pipeline!"); - } - - // write descriptors - IGPUDescriptorSet::SDescriptorInfo infos[3]; - infos[0].desc = m_gpuTlas; - - infos[1].desc = m_hdrImageView; - if (!infos[1].desc) - return logFail("Failed to create image view"); - infos[1].info.image.imageLayout = IImage::LAYOUT::GENERAL; - - infos[2].desc = m_hdrImageView; - infos[2].info.image.imageLayout = IImage::LAYOUT::READ_ONLY_OPTIMAL; - - IGPUDescriptorSet::SWriteDescriptorSet writes[] = { - {.dstSet = m_rayTracingDs.get(), .binding = 0, .arrayElement = 0, .count = 1, .info = &infos[0]}, - {.dstSet = m_rayTracingDs.get(), .binding = 1, .arrayElement = 0, .count = 1, .info = &infos[1]}, - {.dstSet = m_presentDs.get(), .binding = 0, .arrayElement = 0, .count = 1, .info = &infos[2] }, - }; - m_device->updateDescriptorSets(std::span(writes), {}); - - // gui descriptor setup - { - using binding_flags_t = IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS; - { - IGPUSampler::SParams params; - params.AnisotropicFilter = 1u; - params.TextureWrapU = ETC_REPEAT; - params.TextureWrapV = ETC_REPEAT; - params.TextureWrapW = ETC_REPEAT; - - m_ui.samplers.gui = m_device->createSampler(params); - m_ui.samplers.gui->setObjectDebugName("Nabla IMGUI UI Sampler"); - } - - std::array, 69u> immutableSamplers; - for (auto& it : immutableSamplers) - it = smart_refctd_ptr(m_ui.samplers.scene); - - immutableSamplers[nbl::ext::imgui::UI::FontAtlasTexId] = smart_refctd_ptr(m_ui.samplers.gui); - - nbl::ext::imgui::UI::SCreationParameters params; - - params.resources.texturesInfo = { .setIx = 0u, .bindingIx = 0u }; - params.resources.samplersInfo = { .setIx = 0u, .bindingIx = 1u }; - params.assetManager = m_assetMgr; - params.pipelineCache = nullptr; - params.pipelineLayout = nbl::ext::imgui::UI::createDefaultPipelineLayout(m_utils->getLogicalDevice(), params.resources.texturesInfo, params.resources.samplersInfo, MaxUITextureCount); - params.renderpass = smart_refctd_ptr(renderpass); - params.streamingBuffer = nullptr; - params.subpassIx = 0u; - params.transfer = getGraphicsQueue(); - params.utilities = m_utils; - { - m_ui.manager = ext::imgui::UI::create(std::move(params)); - - // note that we use default layout provided by our extension, but you are free to create your own by filling nbl::ext::imgui::UI::S_CREATION_PARAMETERS::resources - const auto* descriptorSetLayout = m_ui.manager->getPipeline()->getLayout()->getDescriptorSetLayout(0u); - const auto& params = m_ui.manager->getCreationParameters(); - - IDescriptorPool::SCreateInfo descriptorPoolInfo = {}; - descriptorPoolInfo.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_SAMPLER)] = (uint32_t)nbl::ext::imgui::UI::DefaultSamplerIx::COUNT; - descriptorPoolInfo.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_SAMPLED_IMAGE)] = MaxUITextureCount; - descriptorPoolInfo.maxSets = 1u; - descriptorPoolInfo.flags = IDescriptorPool::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT; - - m_guiDescriptorSetPool = m_device->createDescriptorPool(std::move(descriptorPoolInfo)); - assert(m_guiDescriptorSetPool); - - m_guiDescriptorSetPool->createDescriptorSets(1u, &descriptorSetLayout, &m_ui.descriptorSet); - assert(m_ui.descriptorSet); - } - } - - m_ui.manager->registerListener( - [this]() -> void { - ImGuiIO& io = ImGui::GetIO(); - - m_camera.setProjectionMatrix([&]() - { - static matrix4SIMD projection; - - projection = matrix4SIMD::buildProjectionMatrixPerspectiveFovRH( - core::radians(m_cameraSetting.fov), - io.DisplaySize.x / io.DisplaySize.y, - m_cameraSetting.zNear, - m_cameraSetting.zFar); - - return projection; - }()); - - ImGui::SetNextWindowPos(ImVec2(1024, 100), ImGuiCond_Appearing); - ImGui::SetNextWindowSize(ImVec2(256, 256), ImGuiCond_Appearing); - - // create a window and insert the inspector - ImGui::SetNextWindowPos(ImVec2(10, 10), ImGuiCond_Appearing); - ImGui::SetNextWindowSize(ImVec2(320, 340), ImGuiCond_Appearing); - ImGui::Begin("Controls"); - - ImGui::SameLine(); - - ImGui::Text("Camera"); - - ImGui::SliderFloat("Move speed", &m_cameraSetting.moveSpeed, 0.1f, 10.f); - ImGui::SliderFloat("Rotate speed", &m_cameraSetting.rotateSpeed, 0.1f, 10.f); - ImGui::SliderFloat("Fov", &m_cameraSetting.fov, 20.f, 150.f); - ImGui::SliderFloat("zNear", &m_cameraSetting.zNear, 0.1f, 100.f); - ImGui::SliderFloat("zFar", &m_cameraSetting.zFar, 110.f, 10000.f); - Light m_oldLight = m_light; - int light_type = m_light.type; - ImGui::ListBox("LightType", &light_type, s_lightTypeNames, ELT_COUNT); - m_light.type = static_cast(light_type); - if (m_light.type == ELT_DIRECTIONAL) - { - ImGui::SliderFloat3("Light Direction", &m_light.direction.x, -1.f, 1.f); - } - else if (m_light.type == ELT_POINT) - { - ImGui::SliderFloat3("Light Position", &m_light.position.x, -20.f, 20.f); - } - else if (m_light.type == ELT_SPOT) - { - ImGui::SliderFloat3("Light Direction", &m_light.direction.x, -1.f, 1.f); - ImGui::SliderFloat3("Light Position", &m_light.position.x, -20.f, 20.f); - - float32_t dOuterCutoff = hlsl::degrees(acos(m_light.outerCutoff)); - if (ImGui::SliderFloat("Light Outer Cutoff", &dOuterCutoff, 0.0f, 45.0f)) - { - m_light.outerCutoff = cos(hlsl::radians(dOuterCutoff)); - } - } - ImGui::Checkbox("Use Indirect Command", &m_useIndirectCommand); - if (m_light != m_oldLight) - { - m_frameAccumulationCounter = 0; - } - - ImGui::Text("X: %f Y: %f", io.MousePos.x, io.MousePos.y); - - ImGui::End(); - } - ); -#endif - // Set Camera - { - core::vectorSIMDf cameraPosition(0, 5, -10); - matrix4SIMD proj = matrix4SIMD::buildProjectionMatrixPerspectiveFovRH( - core::radians(60.0f), - WIN_W / WIN_H, - 0.01f, - 500.0f - ); - m_camera = Camera(cameraPosition, core::vectorSIMDf(0, 0, 0), proj); - } - - m_winMgr->setWindowSize(m_window.get(), WIN_W, WIN_H); - m_surface->recreateSwapchain(); - m_winMgr->show(m_window.get()); - m_oracle.reportBeginFrameRecord(); - m_camera.mapKeysToWASD(); - - return true; - } - - bool updateGUIDescriptorSet() - { - // texture atlas, note we don't create info & write pair for the font sampler because UI extension's is immutable and baked into DS layout - static std::array descriptorInfo; - static IGPUDescriptorSet::SWriteDescriptorSet writes[MaxUITextureCount]; - - descriptorInfo[ext::imgui::UI::FontAtlasTexId].info.image.imageLayout = IImage::LAYOUT::READ_ONLY_OPTIMAL; - descriptorInfo[ext::imgui::UI::FontAtlasTexId].desc = smart_refctd_ptr(m_ui.manager->getFontAtlasView()); - - for (uint32_t i = 0; i < descriptorInfo.size(); ++i) - { - writes[i].dstSet = m_ui.descriptorSet.get(); - writes[i].binding = 0u; - writes[i].arrayElement = i; - writes[i].count = 1u; - } - writes[ext::imgui::UI::FontAtlasTexId].info = descriptorInfo.data() + ext::imgui::UI::FontAtlasTexId; - - return m_device->updateDescriptorSets(writes, {}); - } - - inline void workLoopBody() override - { - // framesInFlight: ensuring safe execution of command buffers and acquires, `framesInFlight` only affect semaphore waits, don't use this to index your resources because it can change with swapchain recreation. - const uint32_t framesInFlight = core::min(MaxFramesInFlight, m_surface->getMaxAcquiresInFlight()); - // We block for semaphores for 2 reasons here: - // A) Resource: Can't use resource like a command buffer BEFORE previous use is finished! [MaxFramesInFlight] - // B) Acquire: Can't have more acquires in flight than a certain threshold returned by swapchain or your surface helper class. [MaxAcquiresInFlight] - if (m_realFrameIx >= framesInFlight) - { - const ISemaphore::SWaitInfo cbDonePending[] = - { - { - .semaphore = m_semaphore.get(), - .value = m_realFrameIx + 1 - framesInFlight - } - }; - if (m_device->blockForSemaphores(cbDonePending) != ISemaphore::WAIT_RESULT::SUCCESS) - return; - } - const auto resourceIx = m_realFrameIx % MaxFramesInFlight; - - m_api->startCapture(); - -// update(); - - auto queue = getGraphicsQueue(); - auto cmdbuf = m_cmdBufs[resourceIx].get(); - - if (!keepRunning()) - return; - - cmdbuf->reset(IGPUCommandBuffer::RESET_FLAGS::RELEASE_RESOURCES_BIT); - cmdbuf->begin(IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT); - cmdbuf->beginDebugMarker("Frame"); -#if 0 - const auto viewMatrix = m_camera.getViewMatrix(); - const auto projectionMatrix = m_camera.getProjectionMatrix(); - const auto viewProjectionMatrix = m_camera.getConcatenatedMatrix(); - - core::matrix3x4SIMD modelMatrix; - modelMatrix.setTranslation(nbl::core::vectorSIMDf(0, 0, 0, 0)); - modelMatrix.setRotation(quaternion(0, 0, 0)); - - core::matrix4SIMD invModelViewProjectionMatrix; - modelViewProjectionMatrix.getInverseTransform(invModelViewProjectionMatrix); - - { - IGPUCommandBuffer::SPipelineBarrierDependencyInfo::image_barrier_t imageBarriers[1]; - imageBarriers[0].barrier = { - .dep = { - .srcStageMask = PIPELINE_STAGE_FLAGS::FRAGMENT_SHADER_BIT, // previous frame read from framgent shader - .srcAccessMask = ACCESS_FLAGS::SHADER_READ_BITS, - .dstStageMask = PIPELINE_STAGE_FLAGS::RAY_TRACING_SHADER_BIT, - .dstAccessMask = ACCESS_FLAGS::SHADER_WRITE_BITS - } - }; - imageBarriers[0].image = m_hdrImage.get(); - imageBarriers[0].subresourceRange = { - .aspectMask = IImage::EAF_COLOR_BIT, - .baseMipLevel = 0u, - .levelCount = 1u, - .baseArrayLayer = 0u, - .layerCount = 1u - }; - imageBarriers[0].oldLayout = m_frameAccumulationCounter == 0 ? IImage::LAYOUT::UNDEFINED : IImage::LAYOUT::READ_ONLY_OPTIMAL; - imageBarriers[0].newLayout = IImage::LAYOUT::GENERAL; - cmdbuf->pipelineBarrier(E_DEPENDENCY_FLAGS::EDF_NONE, { .imgBarriers = imageBarriers }); - } - - // Trace Rays Pass - { - SPushConstants pc; - pc.light = m_light; - pc.proceduralGeomInfoBuffer = m_proceduralGeomInfoBuffer->getDeviceAddress(); - pc.triangleGeomInfoBuffer = m_triangleGeomInfoBuffer->getDeviceAddress(); - pc.frameCounter = m_frameAccumulationCounter; - const core::vector3df camPos = m_camera.getPosition().getAsVector3df(); - pc.camPos = { camPos.X, camPos.Y, camPos.Z }; - memcpy(&pc.invMVP, invModelViewProjectionMatrix.pointer(), sizeof(pc.invMVP)); - - cmdbuf->bindRayTracingPipeline(m_rayTracingPipeline.get()); - cmdbuf->setRayTracingPipelineStackSize(m_rayTracingStackSize); - cmdbuf->pushConstants(m_rayTracingPipeline->getLayout(), IShader::E_SHADER_STAGE::ESS_ALL_RAY_TRACING, 0, sizeof(SPushConstants), &pc); - cmdbuf->bindDescriptorSets(EPBP_RAY_TRACING, m_rayTracingPipeline->getLayout(), 0, 1, &m_rayTracingDs.get()); - if (m_useIndirectCommand) - { - cmdbuf->traceRaysIndirect( - SBufferBinding{ - .offset = 0, - .buffer = m_indirectBuffer, - }); - } - else - { - cmdbuf->traceRays( - m_shaderBindingTable.raygenGroupRange, - m_shaderBindingTable.missGroupsRange, m_shaderBindingTable.missGroupsStride, - m_shaderBindingTable.hitGroupsRange, m_shaderBindingTable.hitGroupsStride, - m_shaderBindingTable.callableGroupsRange, m_shaderBindingTable.callableGroupsStride, - WIN_W, WIN_H, 1); - } - } - - // pipeline barrier - { - IGPUCommandBuffer::SPipelineBarrierDependencyInfo::image_barrier_t imageBarriers[1]; - imageBarriers[0].barrier = { - .dep = { - .srcStageMask = PIPELINE_STAGE_FLAGS::RAY_TRACING_SHADER_BIT, - .srcAccessMask = ACCESS_FLAGS::SHADER_WRITE_BITS, - .dstStageMask = PIPELINE_STAGE_FLAGS::COLOR_ATTACHMENT_OUTPUT_BIT, - .dstAccessMask = ACCESS_FLAGS::COLOR_ATTACHMENT_WRITE_BIT - } - }; - imageBarriers[0].image = m_hdrImage.get(); - imageBarriers[0].subresourceRange = { - .aspectMask = IImage::EAF_COLOR_BIT, - .baseMipLevel = 0u, - .levelCount = 1u, - .baseArrayLayer = 0u, - .layerCount = 1u - }; - imageBarriers[0].oldLayout = IImage::LAYOUT::GENERAL; - imageBarriers[0].newLayout = IImage::LAYOUT::READ_ONLY_OPTIMAL; - - cmdbuf->pipelineBarrier(E_DEPENDENCY_FLAGS::EDF_NONE, { .imgBarriers = imageBarriers }); - } - - { - asset::SViewport viewport; - { - viewport.minDepth = 1.f; - viewport.maxDepth = 0.f; - viewport.x = 0u; - viewport.y = 0u; - viewport.width = WIN_W; - viewport.height = WIN_H; - } - cmdbuf->setViewport(0u, 1u, &viewport); - - - VkRect2D defaultScisors[] = { {.offset = {(int32_t)viewport.x, (int32_t)viewport.y}, .extent = {(uint32_t)viewport.width, (uint32_t)viewport.height}} }; - cmdbuf->setScissor(defaultScisors); - - auto scRes = static_cast(m_surface->getSwapchainResources()); - const VkRect2D currentRenderArea = - { - .offset = {0,0}, - .extent = {m_window->getWidth(),m_window->getHeight()} - }; - const IGPUCommandBuffer::SClearColorValue clearColor = { .float32 = {0.f,0.f,0.f,1.f} }; - const IGPUCommandBuffer::SRenderpassBeginInfo info = - { - .framebuffer = scRes->getFramebuffer(m_currentImageAcquire.imageIndex), - .colorClearValues = &clearColor, - .depthStencilClearValues = nullptr, - .renderArea = currentRenderArea - }; - nbl::video::ISemaphore::SWaitInfo waitInfo = { .semaphore = m_semaphore.get(), .value = m_realFrameIx + 1u }; - - cmdbuf->beginRenderPass(info, IGPUCommandBuffer::SUBPASS_CONTENTS::INLINE); - - cmdbuf->bindGraphicsPipeline(m_presentPipeline.get()); - cmdbuf->bindDescriptorSets(EPBP_GRAPHICS, m_presentPipeline->getLayout(), 0, 1u, &m_presentDs.get()); - ext::FullScreenTriangle::recordDrawCall(cmdbuf); - - const auto uiParams = m_ui.manager->getCreationParameters(); - auto* uiPipeline = m_ui.manager->getPipeline(); - cmdbuf->bindGraphicsPipeline(uiPipeline); - cmdbuf->bindDescriptorSets(EPBP_GRAPHICS, uiPipeline->getLayout(), uiParams.resources.texturesInfo.setIx, 1u, &m_ui.descriptorSet.get()); - m_ui.manager->render(cmdbuf, waitInfo); - - cmdbuf->endRenderPass(); - - } -#endif - cmdbuf->endDebugMarker(); - cmdbuf->end(); - - { - const IQueue::SSubmitInfo::SSemaphoreInfo rendered[] = - { - { - .semaphore = m_semaphore.get(), - .value = ++m_realFrameIx, - .stageMask = PIPELINE_STAGE_FLAGS::ALL_TRANSFER_BITS - } - }; - { - { - const IQueue::SSubmitInfo::SCommandBufferInfo commandBuffers[] = - { - {.cmdbuf = cmdbuf } - }; - - const IQueue::SSubmitInfo::SSemaphoreInfo acquired[] = - { - { - .semaphore = m_currentImageAcquire.semaphore, - .value = m_currentImageAcquire.acquireCount, - .stageMask = PIPELINE_STAGE_FLAGS::NONE - } - }; - const IQueue::SSubmitInfo infos[] = - { - { - .waitSemaphores = acquired, - .commandBuffers = commandBuffers, - .signalSemaphores = rendered - } - }; - -// updateGUIDescriptorSet(); - - if (queue->submit(infos) != IQueue::RESULT::SUCCESS) - m_realFrameIx--; - } - } - - m_window->setCaption("[Nabla Engine] Ray Tracing Pipeline"); - m_surface->present(m_currentImageAcquire.imageIndex, rendered); - } - m_api->endCapture(); - m_frameAccumulationCounter++; - } -#if 0 - inline void update() - { - m_camera.setMoveSpeed(m_cameraSetting.moveSpeed); - m_camera.setRotateSpeed(m_cameraSetting.rotateSpeed); - - static std::chrono::microseconds previousEventTimestamp{}; - - m_inputSystem->getDefaultMouse(&m_mouse); - m_inputSystem->getDefaultKeyboard(&m_keyboard); - - auto updatePresentationTimestamp = [&]() - { - m_currentImageAcquire = m_surface->acquireNextImage(); - - m_oracle.reportEndFrameRecord(); - const auto timestamp = m_oracle.getNextPresentationTimeStamp(); - m_oracle.reportBeginFrameRecord(); - - return timestamp; - }; - - const auto nextPresentationTimestamp = updatePresentationTimestamp(); - - struct - { - std::vector mouse{}; - std::vector keyboard{}; - } capturedEvents; - - m_camera.beginInputProcessing(nextPresentationTimestamp); - { - const auto& io = ImGui::GetIO(); - m_mouse.consumeEvents([&](const IMouseEventChannel::range_t& events) -> void - { - if (!io.WantCaptureMouse) - m_camera.mouseProcess(events); // don't capture the events, only let camera handle them with its impl - - for (const auto& e : events) // here capture - { - if (e.timeStamp < previousEventTimestamp) - continue; - - previousEventTimestamp = e.timeStamp; - capturedEvents.mouse.emplace_back(e); - - } - }, m_logger.get()); - - m_keyboard.consumeEvents([&](const IKeyboardEventChannel::range_t& events) -> void - { - if (!io.WantCaptureKeyboard) - m_camera.keyboardProcess(events); // don't capture the events, only let camera handle them with its impl - - for (const auto& e : events) // here capture - { - if (e.timeStamp < previousEventTimestamp) - continue; - - previousEventTimestamp = e.timeStamp; - capturedEvents.keyboard.emplace_back(e); - } - }, m_logger.get()); - - } - m_camera.endInputProcessing(nextPresentationTimestamp); - - const core::SRange mouseEvents(capturedEvents.mouse.data(), capturedEvents.mouse.data() + capturedEvents.mouse.size()); - const core::SRange keyboardEvents(capturedEvents.keyboard.data(), capturedEvents.keyboard.data() + capturedEvents.keyboard.size()); - const auto cursorPosition = m_window->getCursorControl()->getPosition(); - const auto mousePosition = float32_t2(cursorPosition.x, cursorPosition.y) - float32_t2(m_window->getX(), m_window->getY()); - - const ext::imgui::UI::SUpdateParameters params = - { - .mousePosition = mousePosition, - .displaySize = { m_window->getWidth(), m_window->getHeight() }, - .mouseEvents = mouseEvents, - .keyboardEvents = keyboardEvents - }; - - m_ui.manager->update(params); - } -#endif - inline bool keepRunning() override - { - if (m_surface->irrecoverable()) - return false; - - return true; - } - - inline bool onAppTerminated() override - { - return device_base_t::onAppTerminated(); - } - - private: -#if 0 - bool createAccelerationStructuresFromGeometry(const IGeometryCreator* gc) - { - auto queue = getGraphicsQueue(); - // get geometries into ICPUBuffers - auto pool = m_device->createCommandPool(queue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); - if (!pool) - return logFail("Couldn't create Command Pool for geometry creation!"); - - const auto defaultMaterial = Material{ - .ambient = {0.2, 0.1, 0.1}, - .diffuse = {0.8, 0.3, 0.3}, - .specular = {0.8, 0.8, 0.8}, - .shininess = 1.0f, - .alpha = 1.0f, - }; - - auto getTranslationMatrix = [](float32_t x, float32_t y, float32_t z) - { - core::matrix3x4SIMD transform; - transform.setTranslation(nbl::core::vectorSIMDf(x, y, z, 0)); - return transform; - }; - - core::matrix3x4SIMD planeTransform; - planeTransform.setRotation(quaternion::fromAngleAxis(core::radians(-90.0f), vector3df_SIMD{ 1, 0, 0 })); - - // triangles geometries - const auto cpuObjects = std::array{ - ReferenceObjectCpu { - .meta = {.type = OT_RECTANGLE, .name = "Plane Mesh"}, - .data = gc->createRectangleMesh(nbl::core::vector2df_SIMD(10, 10)), - .material = defaultMaterial, - .transform = planeTransform, - }, - ReferenceObjectCpu { - .meta = {.type = OT_CUBE, .name = "Cube Mesh"}, - .data = gc->createCubeMesh(nbl::core::vector3df(1, 1, 1)), - .material = defaultMaterial, - .transform = getTranslationMatrix(0, 0.5f, 0), - }, - ReferenceObjectCpu { - .meta = {.type = OT_CUBE, .name = "Cube Mesh 2"}, - .data = gc->createCubeMesh(nbl::core::vector3df(1.5, 1.5, 1.5)), - .material = Material{ - .ambient = {0.1, 0.1, 0.2}, - .diffuse = {0.2, 0.2, 0.8}, - .specular = {0.8, 0.8, 0.8}, - .shininess = 1.0f, - }, - .transform = getTranslationMatrix(-5.0f, 1.0f, 0), - }, - ReferenceObjectCpu { - .meta = {.type = OT_CUBE, .name = "Transparent Cube Mesh"}, - .data = gc->createCubeMesh(nbl::core::vector3df(1.5, 1.5, 1.5)), - .material = Material{ - .ambient = {0.1, 0.2, 0.1}, - .diffuse = {0.2, 0.8, 0.2}, - .specular = {0.8, 0.8, 0.8}, - .shininess = 1.0f, - .alpha = 0.2, - }, - .transform = getTranslationMatrix(5.0f, 1.0f, 0), - }, - }; - - struct CPUTriBufferBindings - { - nbl::asset::SBufferBinding vertex, index; - }; - std::array cpuTriBuffers; - - for (uint32_t i = 0; i < cpuObjects.size(); i++) - { - const auto& cpuObject = cpuObjects[i]; - - auto vBuffer = smart_refctd_ptr(cpuObject.data.bindings[0].buffer); // no offset - auto vUsage = bitflag(IGPUBuffer::EUF_STORAGE_BUFFER_BIT) | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_INLINE_UPDATE_VIA_CMDBUF | - IGPUBuffer::EUF_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; - vBuffer->addUsageFlags(vUsage); - vBuffer->setContentHash(vBuffer->computeContentHash()); - - auto iBuffer = smart_refctd_ptr(cpuObject.data.indexBuffer.buffer); // no offset - auto iUsage = bitflag(IGPUBuffer::EUF_STORAGE_BUFFER_BIT) | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_INLINE_UPDATE_VIA_CMDBUF | - IGPUBuffer::EUF_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; - - if (cpuObject.data.indexType != EIT_UNKNOWN) - if (iBuffer) - { - iBuffer->addUsageFlags(iUsage); - iBuffer->setContentHash(iBuffer->computeContentHash()); - } - - cpuTriBuffers[i] = { - .vertex = {.offset = 0, .buffer = vBuffer}, - .index = {.offset = 0, .buffer = iBuffer}, - }; - - } - - // procedural geometries - using Aabb = IGPUBottomLevelAccelerationStructure::AABB_t; - - smart_refctd_ptr cpuProcBuffer; - { - ICPUBuffer::SCreationParams params; - params.size = NumberOfProceduralGeometries * sizeof(Aabb); - cpuProcBuffer = ICPUBuffer::create(std::move(params)); - } - - core::vector proceduralGeoms; - proceduralGeoms.reserve(NumberOfProceduralGeometries); - auto proceduralGeometries = reinterpret_cast(cpuProcBuffer->getPointer()); - for (int32_t i = 0; i < NumberOfProceduralGeometries; i++) - { - const auto middle_i = NumberOfProceduralGeometries / 2.0; - SProceduralGeomInfo sphere = { - .material = hlsl::_static_cast(Material{ - .ambient = {0.1, 0.05 * i, 0.1}, - .diffuse = {0.3, 0.2 * i, 0.3}, - .specular = {0.8, 0.8, 0.8}, - .shininess = 1.0f, - }), - .center = float32_t3((i - middle_i) * 4.0, 2, 5.0), - .radius = 1, - }; - - proceduralGeoms.push_back(sphere); - const auto sphereMin = sphere.center - sphere.radius; - const auto sphereMax = sphere.center + sphere.radius; - proceduralGeometries[i] = { - vector3d(sphereMin.x, sphereMin.y, sphereMin.z), - vector3d(sphereMax.x, sphereMax.y, sphereMax.z) - }; - } - - { - IGPUBuffer::SCreationParams params; - params.usage = IGPUBuffer::EUF_STORAGE_BUFFER_BIT | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_INLINE_UPDATE_VIA_CMDBUF | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; - params.size = proceduralGeoms.size() * sizeof(SProceduralGeomInfo); - m_utils->createFilledDeviceLocalBufferOnDedMem(SIntendedSubmitInfo{ .queue = queue }, std::move(params), proceduralGeoms.data()).move_into(m_proceduralGeomInfoBuffer); - } - - // get ICPUBuffers into ICPUBLAS - // TODO use one BLAS and multiple triangles/aabbs in one - const auto blasCount = std::size(cpuObjects) + 1; - const auto proceduralBlasIdx = std::size(cpuObjects); - - std::array, std::size(cpuObjects)+1u> cpuBlas; - for (uint32_t i = 0; i < blasCount; i++) - { - auto& blas = cpuBlas[i]; - blas = make_smart_refctd_ptr(); - - if (i == proceduralBlasIdx) - { - auto aabbs = make_refctd_dynamic_array>>(1u); - auto primitiveCounts = make_refctd_dynamic_array>(1u); - - auto& aabb = aabbs->front(); - auto& primCount = primitiveCounts->front(); - - primCount = NumberOfProceduralGeometries; - aabb.data = { .offset = 0, .buffer = cpuProcBuffer }; - aabb.stride = sizeof(IGPUBottomLevelAccelerationStructure::AABB_t); - aabb.geometryFlags = IGPUBottomLevelAccelerationStructure::GEOMETRY_FLAGS::OPAQUE_BIT; // only allow opaque for now - - blas->setGeometries(std::move(aabbs), std::move(primitiveCounts)); - } - else - { - auto triangles = make_refctd_dynamic_array>>(1u); - auto primitiveCounts = make_refctd_dynamic_array>(1u); - - auto& tri = triangles->front(); - auto& primCount = primitiveCounts->front(); - const auto& geom = cpuObjects[i]; - const auto& cpuBuf = cpuTriBuffers[i]; - - const bool useIndex = geom.data.indexType != EIT_UNKNOWN; - const uint32_t vertexStride = geom.data.inputParams.bindings[0].stride; - const uint32_t numVertices = cpuBuf.vertex.buffer->getSize() / vertexStride; - - if (useIndex) - primCount = geom.data.indexCount / 3; - else - primCount = numVertices / 3; - - tri.vertexData[0] = cpuBuf.vertex; - tri.indexData = useIndex ? cpuBuf.index : cpuBuf.vertex; - tri.maxVertex = numVertices - 1; - tri.vertexStride = vertexStride; - tri.vertexFormat = EF_R32G32B32_SFLOAT; - tri.indexType = geom.data.indexType; - tri.geometryFlags = geom.material.isTransparent() ? - IGPUBottomLevelAccelerationStructure::GEOMETRY_FLAGS::NO_DUPLICATE_ANY_HIT_INVOCATION_BIT : - IGPUBottomLevelAccelerationStructure::GEOMETRY_FLAGS::OPAQUE_BIT; - - blas->setGeometries(std::move(triangles), std::move(primitiveCounts)); - } - - auto blasFlags = bitflag(IGPUBottomLevelAccelerationStructure::BUILD_FLAGS::PREFER_FAST_TRACE_BIT) | IGPUBottomLevelAccelerationStructure::BUILD_FLAGS::ALLOW_COMPACTION_BIT; - if (i == proceduralBlasIdx) - blasFlags |= IGPUBottomLevelAccelerationStructure::BUILD_FLAGS::GEOMETRY_TYPE_IS_AABB_BIT; - - blas->setBuildFlags(blasFlags); - blas->setContentHash(blas->computeContentHash()); - } - - auto geomInfoBuffer = ICPUBuffer::create({ std::size(cpuObjects) * sizeof(STriangleGeomInfo) }); - STriangleGeomInfo* geomInfos = reinterpret_cast(geomInfoBuffer->getPointer()); - - // get ICPUBLAS into ICPUTLAS - auto geomInstances = make_refctd_dynamic_array>(blasCount); - { - uint32_t i = 0; - for (auto instance = geomInstances->begin(); instance != geomInstances->end(); instance++, i++) - { - const auto isProceduralInstance = i == proceduralBlasIdx; - ICPUTopLevelAccelerationStructure::StaticInstance inst; - inst.base.blas = cpuBlas[i]; - inst.base.flags = static_cast(IGPUTopLevelAccelerationStructure::INSTANCE_FLAGS::TRIANGLE_FACING_CULL_DISABLE_BIT); - inst.base.instanceCustomIndex = i; - inst.base.instanceShaderBindingTableRecordOffset = isProceduralInstance ? 2 : 0;; - inst.base.mask = 0xFF; - inst.transform = isProceduralInstance ? matrix3x4SIMD() : cpuObjects[i].transform; - - instance->instance = inst; - } - } - - auto cpuTlas = make_smart_refctd_ptr(); - cpuTlas->setInstances(std::move(geomInstances)); - cpuTlas->setBuildFlags(IGPUTopLevelAccelerationStructure::BUILD_FLAGS::PREFER_FAST_TRACE_BIT); - - // convert with asset converter - smart_refctd_ptr converter = CAssetConverter::create({ .device = m_device.get(), .optimizer = {} }); - struct MyInputs : CAssetConverter::SInputs - { - // For the GPU Buffers to be directly writeable and so that we don't need a Transfer Queue submit at all - inline uint32_t constrainMemoryTypeBits(const size_t groupCopyID, const IAsset* canonicalAsset, const blake3_hash_t& contentHash, const IDeviceMemoryBacked* memoryBacked) const override - { - assert(memoryBacked); - return memoryBacked->getObjectType() != IDeviceMemoryBacked::EOT_BUFFER ? (~0u) : rebarMemoryTypes; - } - - uint32_t rebarMemoryTypes; - } inputs = {}; - inputs.logger = m_logger.get(); - inputs.rebarMemoryTypes = m_physicalDevice->getDirectVRAMAccessMemoryTypeBits(); - // the allocator needs to be overriden to hand out memory ranges which have already been mapped so that the ReBAR fast-path can kick in - // (multiple buffers can be bound to same memory, but memory can only be mapped once at one place, so Asset Converter can't do it) - struct MyAllocator final : public IDeviceMemoryAllocator - { - ILogicalDevice* getDeviceForAllocations() const override { return device; } - - SAllocation allocate(const SAllocateInfo& info) override - { - auto retval = device->allocate(info); - // map what is mappable by default so ReBAR checks succeed - if (retval.isValid() && retval.memory->isMappable()) - retval.memory->map({ .offset = 0,.length = info.size }); - return retval; - } - - ILogicalDevice* device; - } myalloc; - myalloc.device = m_device.get(); - inputs.allocator = &myalloc; - - std::array tmpTlas; - std::array tmpBuffers; - { - tmpTlas[0] = cpuTlas.get(); - for (uint32_t i = 0; i < cpuObjects.size(); i++) - { - tmpBuffers[2 * i + 0] = cpuTriBuffers[i].vertex.buffer.get(); - tmpBuffers[2 * i + 1] = cpuTriBuffers[i].index.buffer.get(); - } - tmpBuffers[2 * proceduralBlasIdx] = cpuProcBuffer.get(); - - std::get>(inputs.assets) = tmpTlas; - std::get>(inputs.assets) = tmpBuffers; - } - - auto reservation = converter->reserve(inputs); - { - auto prepass = [&](const auto & references) -> bool - { - auto objects = reservation.getGPUObjects(); - uint32_t counter = {}; - for (auto& object : objects) - { - auto gpu = object.value; - auto* reference = references[counter]; - - if (reference) - { - if (!gpu) - { - m_logger->log("Failed to convert a CPU object to GPU!", ILogger::ELL_ERROR); - return false; - } - } - counter++; - } - return true; - }; - - prepass.template operator() < ICPUTopLevelAccelerationStructure > (tmpTlas); - prepass.template operator() < ICPUBuffer > (tmpBuffers); - } - - constexpr auto CompBufferCount = 2; - std::array, CompBufferCount> compBufs = {}; - std::array compBufInfos = {}; - { - auto pool = m_device->createCommandPool(queue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT | IGPUCommandPool::CREATE_FLAGS::TRANSIENT_BIT); - pool->createCommandBuffers(IGPUCommandPool::BUFFER_LEVEL::PRIMARY, compBufs); - compBufs.front()->begin(IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT); - for (auto i = 0; i < CompBufferCount; i++) - compBufInfos[i].cmdbuf = compBufs[i].get(); - } - auto compSema = m_device->createSemaphore(0u); - SIntendedSubmitInfo compute = {}; - compute.queue = queue; - compute.scratchCommandBuffers = compBufInfos; - compute.scratchSemaphore = { - .semaphore = compSema.get(), - .value = 0u, - .stageMask = PIPELINE_STAGE_FLAGS::ACCELERATION_STRUCTURE_BUILD_BIT | PIPELINE_STAGE_FLAGS::ACCELERATION_STRUCTURE_COPY_BIT - }; - // convert - { - smart_refctd_ptr scratchAlloc; - { - constexpr auto MaxAlignment = 256; - constexpr auto MinAllocationSize = 1024; - const auto scratchSize = core::alignUp(reservation.getMaxASBuildScratchSize(false), MaxAlignment); - - - IGPUBuffer::SCreationParams creationParams = {}; - creationParams.size = scratchSize; - creationParams.usage = IGPUBuffer::EUF_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT | IGPUBuffer::EUF_STORAGE_BUFFER_BIT; - auto scratchBuffer = m_device->createBuffer(std::move(creationParams)); - - auto reqs = scratchBuffer->getMemoryReqs(); - reqs.memoryTypeBits &= m_physicalDevice->getDirectVRAMAccessMemoryTypeBits(); - - auto allocation = m_device->allocate(reqs, scratchBuffer.get(), IDeviceMemoryAllocation::EMAF_DEVICE_ADDRESS_BIT); - allocation.memory->map({ .offset = 0,.length = reqs.size }); - - scratchAlloc = make_smart_refctd_ptr( - SBufferRange{0ull, scratchSize, std::move(scratchBuffer)}, - core::allocator(), MaxAlignment, MinAllocationSize - ); - } - - struct MyParams final : CAssetConverter::SConvertParams - { - inline uint32_t getFinalOwnerQueueFamily(const IGPUBuffer* buffer, const core::blake3_hash_t& createdFrom) override - { - return finalUser; - } - inline uint32_t getFinalOwnerQueueFamily(const IGPUAccelerationStructure* image, const core::blake3_hash_t& createdFrom) override - { - return finalUser; - } - - uint8_t finalUser; - } params = {}; - params.utilities = m_utils.get(); - params.compute = &compute; - params.scratchForDeviceASBuild = scratchAlloc.get(); - params.finalUser = queue->getFamilyIndex(); - - auto future = reservation.convert(params); - if (future.copy() != IQueue::RESULT::SUCCESS) - { - m_logger->log("Failed to await submission feature!", ILogger::ELL_ERROR); - return false; - } - // 2 submits, BLAS build, TLAS build, DO NOT ADD COMPACTIONS IN THIS EXAMPLE! - if (compute.getFutureScratchSemaphore().value>3) - m_logger->log("Overflow submitted on Compute Queue despite using ReBAR (no transfer submits or usage of staging buffer) and providing a AS Build Scratch Buffer of correctly queried max size!",system::ILogger::ELL_ERROR); - - // assign gpu objects to output - auto&& tlases = reservation.getGPUObjects(); - m_gpuTlas = tlases[0].value; - auto&& buffers = reservation.getGPUObjects(); - for (uint32_t i = 0; i < cpuObjects.size(); i++) - { - auto& cpuObject = cpuObjects[i]; - - m_gpuTriangleGeometries.push_back(ReferenceObjectGpu{ - .meta = cpuObject.meta, - .bindings = { - .vertex = {.offset = 0, .buffer = buffers[2 * i + 0].value }, - .index = {.offset = 0, .buffer = buffers[2 * i + 1].value }, - }, - .vertexStride = cpuObject.data.inputParams.bindings[0].stride, - .indexType = cpuObject.data.indexType, - .indexCount = cpuObject.data.indexCount, - .material = hlsl::_static_cast(cpuObject.material), - .transform = cpuObject.transform, - }); - } - m_proceduralAabbBuffer = buffers[2 * proceduralBlasIdx].value; - - for (uint32_t i = 0; i < m_gpuTriangleGeometries.size(); i++) - { - const auto& gpuObject = m_gpuTriangleGeometries[i]; - const uint64_t vertexBufferAddress = gpuObject.bindings.vertex.buffer->getDeviceAddress(); - geomInfos[i] = { - .material = gpuObject.material, - .vertexBufferAddress = vertexBufferAddress, - .indexBufferAddress = gpuObject.useIndex() ? gpuObject.bindings.index.buffer->getDeviceAddress() : vertexBufferAddress, - .vertexStride = gpuObject.vertexStride, - .objType = gpuObject.meta.type, - .indexType = gpuObject.indexType, - .smoothNormals = s_smoothNormals[gpuObject.meta.type], - }; - } - } - - { - IGPUBuffer::SCreationParams params; - params.usage = IGPUBuffer::EUF_STORAGE_BUFFER_BIT | IGPUBuffer::EUF_TRANSFER_DST_BIT | IGPUBuffer::EUF_INLINE_UPDATE_VIA_CMDBUF | IGPUBuffer::EUF_SHADER_DEVICE_ADDRESS_BIT; - params.size = geomInfoBuffer->getSize(); - m_utils->createFilledDeviceLocalBufferOnDedMem(SIntendedSubmitInfo{ .queue = queue }, std::move(params), geomInfos).move_into(m_triangleGeomInfoBuffer); - } - - return true; - } -#endif - smart_refctd_ptr m_converter; - - smart_refctd_ptr m_window; - smart_refctd_ptr> m_surface; - smart_refctd_ptr m_semaphore; - uint64_t m_realFrameIx = 0; -uint32_t m_frameAccumulationCounter = 0; - std::array, MaxFramesInFlight> m_cmdBufs; - ISimpleManagedSurface::SAcquireResult m_currentImageAcquire = {}; - - core::smart_refctd_ptr m_inputSystem; - InputSystem::ChannelReader m_mouse; - InputSystem::ChannelReader m_keyboard; - - struct CameraSetting - { - float fov = 60.f; - float zNear = 0.1f; - float zFar = 10000.f; - float moveSpeed = 1.f; - float rotateSpeed = 1.f; - float viewWidth = 10.f; - float camYAngle = 165.f / 180.f * 3.14159f; - float camXAngle = 32.f / 180.f * 3.14159f; - - } m_cameraSetting; - Camera m_camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); - - video::CDumbPresentationOracle m_oracle; - -#if 0 - struct C_UI - { - nbl::core::smart_refctd_ptr manager; - - struct - { - core::smart_refctd_ptr gui, scene; - } samplers; - - core::smart_refctd_ptr descriptorSet; - } m_ui; - core::smart_refctd_ptr m_guiDescriptorSetPool; - - core::vector m_gpuTriangleGeometries; - core::vector m_gpuIntersectionSpheres; - uint32_t m_intersectionHitGroupIdx; - - smart_refctd_ptr m_gpuTlas; - smart_refctd_ptr m_instanceBuffer; - - smart_refctd_ptr m_triangleGeomInfoBuffer; - smart_refctd_ptr m_proceduralGeomInfoBuffer; - smart_refctd_ptr m_proceduralAabbBuffer; - smart_refctd_ptr m_indirectBuffer; - - smart_refctd_ptr m_hdrImage; - smart_refctd_ptr m_hdrImageView; - - smart_refctd_ptr m_rayTracingDsPool; - smart_refctd_ptr m_rayTracingDs; - smart_refctd_ptr m_rayTracingPipeline; - uint64_t m_rayTracingStackSize; - ShaderBindingTable m_shaderBindingTable; - - smart_refctd_ptr m_presentDs; - smart_refctd_ptr m_presentDsPool; - smart_refctd_ptr m_presentPipeline; - -#endif -}; -NBL_MAIN_FUNC(MeshLoadersApp) diff --git a/29_MeshLoaders/pipeline.groovy b/29_MeshLoaders/pipeline.groovy deleted file mode 100644 index 9a89cc786..000000000 --- a/29_MeshLoaders/pipeline.groovy +++ /dev/null @@ -1,50 +0,0 @@ -import org.DevshGraphicsProgramming.Agent -import org.DevshGraphicsProgramming.BuilderInfo -import org.DevshGraphicsProgramming.IBuilder - -class CPLYSTLDemoBuilder extends IBuilder -{ - public CPLYSTLDemoBuilder(Agent _agent, _info) - { - super(_agent, _info) - } - - @Override - public boolean prepare(Map axisMapping) - { - return true - } - - @Override - public boolean build(Map axisMapping) - { - IBuilder.CONFIGURATION config = axisMapping.get("CONFIGURATION") - IBuilder.BUILD_TYPE buildType = axisMapping.get("BUILD_TYPE") - - def nameOfBuildDirectory = getNameOfBuildDirectory(buildType) - def nameOfConfig = getNameOfConfig(config) - - agent.execute("cmake --build ${info.rootProjectPath}/${nameOfBuildDirectory}/${info.targetProjectPathRelativeToRoot} --target ${info.targetBaseName} --config ${nameOfConfig} -j12 -v") - - return true - } - - @Override - public boolean test(Map axisMapping) - { - return true - } - - @Override - public boolean install(Map axisMapping) - { - return true - } -} - -def create(Agent _agent, _info) -{ - return new CPLYSTLDemoBuilder(_agent, _info) -} - -return this \ No newline at end of file From 4f1fabdb786b87e4609649a36059c33cd54ae843 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 9 Jul 2025 15:19:03 +0700 Subject: [PATCH 18/18] add debug aabb draws around mesh --- 12_MeshLoaders/CMakeLists.txt | 8 ++++- 12_MeshLoaders/main.cpp | 58 +++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/12_MeshLoaders/CMakeLists.txt b/12_MeshLoaders/CMakeLists.txt index dee195066..3743e57cb 100644 --- a/12_MeshLoaders/CMakeLists.txt +++ b/12_MeshLoaders/CMakeLists.txt @@ -15,4 +15,10 @@ endif() # TODO; Arek I removed `NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET` from the last parameter here, doesn't this macro have 4 arguments anyway !? nbl_create_executable_project("" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}") # TODO: Arek temporarily disabled cause I haven't figured out how to make this target yet -# LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} nblExamplesGeometrySpirvBRD) \ No newline at end of file +# LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} nblExamplesGeometrySpirvBRD) + +if (NBL_BUILD_DEBUG_DRAW) + add_dependencies(${EXECUTABLE_NAME} ${NBL_EXT_DEBUG_DRAW_TARGET}) + target_link_libraries(${EXECUTABLE_NAME} PRIVATE ${NBL_EXT_DEBUG_DRAW_TARGET}) + target_include_directories(${EXECUTABLE_NAME} PUBLIC $) +endif() diff --git a/12_MeshLoaders/main.cpp b/12_MeshLoaders/main.cpp index 3a4d8b13b..4d57eb18e 100644 --- a/12_MeshLoaders/main.cpp +++ b/12_MeshLoaders/main.cpp @@ -9,6 +9,10 @@ #include "nbl/ext/MitsubaLoader/CSerializedLoader.h" #endif +#ifdef NBL_BUILD_DEBUG_DRAW +#include "nbl/ext/DebugDraw/CDrawAABB.h" +#endif + class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourcesApplication { using device_base_t = MonoWindowApplication; @@ -48,6 +52,18 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc if (!m_renderer) return logFail("Failed to create renderer!"); +#ifdef NBL_BUILD_DEBUG_DRAW + { + auto* renderpass = scRes->getRenderpass(); + ext::debugdraw::DrawAABB::SCreationParameters params = {}; + params.assetManager = m_assetMgr; + params.pipelineLayout = ext::debugdraw::DrawAABB::createDefaultPipelineLayout(m_device.get()); + params.renderpass = smart_refctd_ptr(renderpass); + params.utilities = m_utils; + drawAABB = ext::debugdraw::DrawAABB::create(std::move(params)); + } +#endif + // if (!reloadModel()) return false; @@ -109,8 +125,12 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc keyboard.consumeEvents([&](const IKeyboardEventChannel::range_t& events) -> void { for (const auto& event : events) - if (event.keyCode==E_KEY_CODE::EKC_R && event.action==SKeyboardEvent::ECA_RELEASED) - reload = true; + { + if (event.keyCode == E_KEY_CODE::EKC_R && event.action == SKeyboardEvent::ECA_RELEASED) + reload = true; + if (event.keyCode == E_KEY_CODE::EKC_B && event.action == SKeyboardEvent::ECA_RELEASED) + m_drawBBs = !m_drawBBs; + } camera.keyboardProcess(events); }, m_logger.get() @@ -130,6 +150,24 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc } m_renderer->render(cb,CSimpleDebugRenderer::SViewParams(viewMatrix,viewProjMatrix)); } +#ifdef NBL_BUILD_DEBUG_DRAW + if (m_drawBBs) + { + core::matrix4SIMD modelViewProjectionMatrix; + { + const auto viewMatrix = camera.getViewMatrix(); + const auto projectionMatrix = camera.getProjectionMatrix(); + const auto viewProjectionMatrix = camera.getConcatenatedMatrix(); + + core::matrix3x4SIMD modelMatrix; + modelMatrix.setTranslation(nbl::core::vectorSIMDf(0, 0, 0, 0)); + modelMatrix.setRotation(quaternion(0, 0, 0)); + modelViewProjectionMatrix = core::concatenateBFollowedByA(viewProjectionMatrix, modelMatrix); + } + const ISemaphore::SWaitInfo drawFinished = { .semaphore = m_semaphore.get(),.value = m_realFrameIx + 1u }; + drawAABB->render(cb, drawFinished, modelViewProjectionMatrix.pointer()); + } +#endif cb->endRenderPass(); } cb->end(); @@ -349,7 +387,10 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc return false; } } - + +#ifdef NBL_BUILD_DEBUG_DRAW + drawAABB->clearAABBs(); +#endif auto tmp = hlsl::float32_t4x3( hlsl::float32_t3(1,0,0), hlsl::float32_t3(0,1,0), @@ -367,6 +408,12 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc const auto transformed = hlsl::shapes::util::transform(promotedWorld,promoted); printAABB(transformed,"Transformed"); bound = hlsl::shapes::util::union_(transformed,bound); + +#ifdef NBL_BUILD_DEBUG_DRAW + const auto tmpAabb = shapes::AABB<3,float>(promoted.minVx, promoted.maxVx); + const auto tmpWorld = hlsl::float32_t3x4(promotedWorld); + drawAABB->addOBB(tmpAabb, tmpWorld, hlsl::float32_t4{ 1,1,1,1 }); +#endif } printAABB(bound,"Total"); if (!m_renderer->addGeometries({ &converted.front().get(),converted.size() })) @@ -416,6 +463,11 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc Camera camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); // mutables std::string m_modelPath; + + bool m_drawBBs = true; +#ifdef NBL_BUILD_DEBUG_DRAW + smart_refctd_ptr drawAABB; +#endif }; NBL_MAIN_FUNC(MeshLoadersApp) \ No newline at end of file