diff --git a/include/vsg/app/CommandGraph.h b/include/vsg/app/CommandGraph.h index f189b82e6d..da10785949 100644 --- a/include/vsg/app/CommandGraph.h +++ b/include/vsg/app/CommandGraph.h @@ -41,11 +41,7 @@ namespace vsg uint32_t maxSlot = 2; int submitOrder = 0; - inline ref_ptr getOrCreateRecordTraversal() - { - if (!recordTraversal) recordTraversal = RecordTraversal::create(maxSlot); - return recordTraversal; - } + ref_ptr getOrCreateRecordTraversal(); ref_ptr recordTraversal; @@ -53,6 +49,9 @@ namespace vsg virtual void reset(); virtual void record(ref_ptr recordedCommandBuffers, ref_ptr frameStamp = {}, ref_ptr databasePager = {}); + /// hook for assigning Instrumentation to enable profiling of record traversal. + ref_ptr instrumentation; + protected: virtual ~CommandGraph(); diff --git a/include/vsg/app/RecordAndSubmitTask.h b/include/vsg/app/RecordAndSubmitTask.h index c8b2c5a4b4..36599d703e 100644 --- a/include/vsg/app/RecordAndSubmitTask.h +++ b/include/vsg/app/RecordAndSubmitTask.h @@ -59,6 +59,9 @@ namespace vsg ref_ptr databasePager; + /// hook for assigning Instrumentation to enable profiling of record traversal. + ref_ptr instrumentation; + protected: size_t _currentFrameIndex; std::vector _indices; diff --git a/include/vsg/app/RecordTraversal.h b/include/vsg/app/RecordTraversal.h index a120e7be97..db9747a406 100644 --- a/include/vsg/app/RecordTraversal.h +++ b/include/vsg/app/RecordTraversal.h @@ -53,6 +53,7 @@ namespace vsg class SpotLight; class CommandGraph; class RecordedCommandBuffers; + class Instrumentation; VSG_type_name(vsg::RecordTraversal); @@ -128,6 +129,9 @@ namespace vsg // clear the bins to record a new frame. void clearBins(); + /// hook for assigning Instrumentation to enable profiling of record traversal. + ref_ptr instrumentation; + protected: virtual ~RecordTraversal(); diff --git a/include/vsg/app/Viewer.h b/include/vsg/app/Viewer.h index 513b6f9112..17fcb8dc80 100644 --- a/include/vsg/app/Viewer.h +++ b/include/vsg/app/Viewer.h @@ -133,6 +133,9 @@ namespace vsg /// Call vkDeviceWaitIdle on all the devices associated with this Viewer virtual void deviceWaitIdle() const; + /// hook for assigning Instrumentation to enable profiling of record traversal. + ref_ptr instrumentation; + protected: virtual ~Viewer(); diff --git a/include/vsg/utils/Instrumentation.h b/include/vsg/utils/Instrumentation.h new file mode 100644 index 0000000000..9b25006cb0 --- /dev/null +++ b/include/vsg/utils/Instrumentation.h @@ -0,0 +1,92 @@ +#pragma once + +/* + +Copyright(c) 2023 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +namespace vsg +{ + + #if defined ( __clang__ ) || defined ( __GNUC__ ) + # define VsgFunctionName __PRETTY_FUNCTION__ + #elif defined ( _MSC_VER ) + # define VsgFunctionName __FUNCSIG__ + #endif + + class CommandBuffer; + + /// SourceLocation structs mark the location in a source file when instrumentation is placed. + /// Memory layout was chosen to be compatible to Tracy's SourceLocationData object. + struct SourceLocation + { + const char* name; + const char* function; + const char* file; + uint32_t line; + ubvec4 color; + }; + + /// base class for Instrumentation implentations + class VSG_DECLSPEC Instrumentation : public Inherit + { + public: + + Instrumentation(); + + virtual void enter(const SourceLocation* sl, uint64_t& reference) const= 0; + virtual void leave(const SourceLocation* sl, uint64_t& reference) const = 0; + + ref_ptr commandBuffer; + + protected: + + virtual ~Instrumentation(); + + }; + VSG_type_name(vsg::Instrumentation); + + /// Concrete Implementation that uses VK_debug_utils to emit annotation to scene graph traversal. + /// Provides tools like RenderDoc a way to report the source location associated with Vulkan calls. + class VSG_DECLSPEC VulkanAnnotation : public Inherit + { + public: + + VulkanAnnotation(); + + virtual void enter(const SourceLocation* sl, uint64_t& reference) const; + virtual void leave(const SourceLocation* sl, uint64_t& reference) const; + + protected: + + virtual ~VulkanAnnotation(); + + }; + VSG_type_name(vsg::VulkanAnnotation); + + struct ScopedInstrumentation + { + const Instrumentation* instr; + const SourceLocation* sl; + uint64_t reference; + inline ScopedInstrumentation(const Instrumentation* in_instr, const SourceLocation* in_sl) : instr(in_instr), sl(in_sl) { if (instr) instr->enter(sl, reference); } + inline ~ScopedInstrumentation() { if (instr) instr->leave(sl, reference); } + }; + + #define SCOPED_INSTRUMENTASTION(instrumentation) static constexpr SourceLocation s_source_location_##__LINE__ { nullptr, VsgFunctionName, __FILE__, __LINE__, ubvec4(255, 255, 255, 255) }; ScopedInstrumentation __scoped_instrumentation(instrumentation, &(s_source_location_##__LINE__)); + #define SCOPED_INSTRUMENTASTION_N(instrumentation, name) static constexpr SourceLocation s_source_location_##__LINE__ { name, VsgFunctionName, __FILE__, __LINE__, ubvec4(255, 255, 255, 255) }; ScopedInstrumentation __scoped_instrumentation(instrumentation, &(s_source_location_##__LINE__)); + #define SCOPED_INSTRUMENTASTION_C(instrumentation, color) static constexpr SourceLocation s_source_location_##__LINE__ { nullptr, VsgFunctionName, __FILE__, __LINE__, color }; ScopedInstrumentation __scoped_instrumentation(instrumentation, &(s_source_location_##__LINE__)); + #define SCOPED_INSTRUMENTASTION_NC(instrumentation, name, color) static constexpr SourceLocation s_source_location_##__LINE__ { name, VsgFunctionName, __FILE__, __LINE__, color }; ScopedInstrumentation __scoped_instrumentation(instrumentation, &(s_source_location_##__LINE__)); + +} // namespace vsg diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 6932475556..4c7320325c 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -223,6 +223,7 @@ set(SOURCES utils/ShaderCompiler.cpp utils/ComputeBounds.cpp utils/Intersector.cpp + utils/Instrumentation.cpp utils/LineSegmentIntersector.cpp utils/LoadPagedLOD.cpp ) diff --git a/src/vsg/app/CommandGraph.cpp b/src/vsg/app/CommandGraph.cpp index dd4cf4b502..6a93d388dc 100644 --- a/src/vsg/app/CommandGraph.cpp +++ b/src/vsg/app/CommandGraph.cpp @@ -17,11 +17,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include using namespace vsg; CommandGraph::CommandGraph() { + SCOPED_INSTRUMENTASTION(instrumentation); } CommandGraph::CommandGraph(ref_ptr in_device, int family) : @@ -29,12 +31,15 @@ CommandGraph::CommandGraph(ref_ptr in_device, int family) : queueFamily(family), presentFamily(-1) { + SCOPED_INSTRUMENTASTION(instrumentation); } CommandGraph::CommandGraph(ref_ptr in_window, ref_ptr child) : window(in_window), device(in_window->getOrCreateDevice()) { + SCOPED_INSTRUMENTASTION(instrumentation); + VkQueueFlags queueFlags = VK_QUEUE_GRAPHICS_BIT; if (window->traits()) queueFlags = window->traits()->queueFlags; @@ -45,6 +50,7 @@ CommandGraph::CommandGraph(ref_ptr in_window, ref_ptr child) : CommandGraph::~CommandGraph() { + SCOPED_INSTRUMENTASTION(instrumentation); } VkCommandBufferLevel CommandGraph::level() const @@ -56,8 +62,28 @@ void CommandGraph::reset() { } +ref_ptr CommandGraph::getOrCreateRecordTraversal() +{ + SCOPED_INSTRUMENTASTION(instrumentation); + + if (!recordTraversal) + { + recordTraversal = RecordTraversal::create(maxSlot); + if (!recordTraversal->instrumentation && window && window->traits() && window->traits()->apiDumpLayer) + { + recordTraversal->instrumentation = VulkanAnnotation::create(); + } + + info("CommandGraph::getOrCreateRecordTraversal() ", recordTraversal); + } + return recordTraversal; +} + + void CommandGraph::record(ref_ptr recordedCommandBuffers, ref_ptr frameStamp, ref_ptr databasePager) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (window && !window->visible()) { return; @@ -100,6 +126,7 @@ void CommandGraph::record(ref_ptr recordedCommandBuffers recordTraversal->getState()->_commandBuffer = commandBuffer; + // or select index when maps to a dormant CommandBuffer VkCommandBuffer vk_commandBuffer = *commandBuffer; @@ -112,10 +139,22 @@ void CommandGraph::record(ref_ptr recordedCommandBuffers vkBeginCommandBuffer(vk_commandBuffer, &beginInfo); + if (recordTraversal->instrumentation) + { + // attach the commandBuffer to instrumentation so it can be recorded to if required. + recordTraversal->instrumentation->commandBuffer = commandBuffer; + } + traverse(*recordTraversal); vkEndCommandBuffer(vk_commandBuffer); + if (recordTraversal->instrumentation) + { + // disconnect the commandBuffer from instrumentation as it's no longer valid for recording commands to + recordTraversal->instrumentation->commandBuffer = {}; + } + recordedCommandBuffers->add(submitOrder, commandBuffer); } diff --git a/src/vsg/app/RecordAndSubmitTask.cpp b/src/vsg/app/RecordAndSubmitTask.cpp index 404188ae7b..6a49cbf6bf 100644 --- a/src/vsg/app/RecordAndSubmitTask.cpp +++ b/src/vsg/app/RecordAndSubmitTask.cpp @@ -15,12 +15,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include using namespace vsg; RecordAndSubmitTask::RecordAndSubmitTask(Device* in_device, uint32_t numBuffers) : device(in_device) { + SCOPED_INSTRUMENTASTION(instrumentation); + _currentFrameIndex = numBuffers; // numBuffers is used to signify unset value for (uint32_t i = 0; i < numBuffers; ++i) { @@ -42,6 +45,8 @@ RecordAndSubmitTask::RecordAndSubmitTask(Device* in_device, uint32_t numBuffers) void RecordAndSubmitTask::advance() { + SCOPED_INSTRUMENTASTION(instrumentation); + if (_currentFrameIndex >= _indices.size()) { // first frame so set to 0 @@ -80,6 +85,8 @@ Fence* RecordAndSubmitTask::fence(size_t relativeFrameIndex) VkResult RecordAndSubmitTask::submit(ref_ptr frameStamp) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (VkResult result = start(); result != VK_SUCCESS) return result; if (earlyTransferTask) @@ -96,6 +103,8 @@ VkResult RecordAndSubmitTask::submit(ref_ptr frameStamp) VkResult RecordAndSubmitTask::start() { + SCOPED_INSTRUMENTASTION(instrumentation); + if (earlyTransferTask) earlyTransferTask->currentTransferCompletedSemaphore = {}; if (lateTransferTask) lateTransferTask->currentTransferCompletedSemaphore = {}; @@ -112,6 +121,8 @@ VkResult RecordAndSubmitTask::start() VkResult RecordAndSubmitTask::record(ref_ptr recordedCommandBuffers, ref_ptr frameStamp) { + SCOPED_INSTRUMENTASTION(instrumentation); + for (auto& commandGraph : commandGraphs) { commandGraph->record(recordedCommandBuffers, frameStamp, databasePager); @@ -122,6 +133,8 @@ VkResult RecordAndSubmitTask::record(ref_ptr recordedCom VkResult RecordAndSubmitTask::finish(ref_ptr recordedCommandBuffers) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (lateTransferTask) { if (VkResult result = lateTransferTask->transferDynamicData(); result != VK_SUCCESS) return result; diff --git a/src/vsg/app/RecordTraversal.cpp b/src/vsg/app/RecordTraversal.cpp index d2b57af527..0c661578e1 100644 --- a/src/vsg/app/RecordTraversal.cpp +++ b/src/vsg/app/RecordTraversal.cpp @@ -39,6 +39,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include + + using namespace vsg; #define INLINE_TRAVERSE 0 @@ -46,6 +49,9 @@ using namespace vsg; RecordTraversal::RecordTraversal(uint32_t in_maxSlot, std::set in_bins) : _state(new State(in_maxSlot)) { + // instrumentation = Instrumentation::create(); + SCOPED_INSTRUMENTASTION_C(instrumentation, ubvec4(0, 0, 255, 255)); + _minimumBinNumber = 0; int32_t maximumBinNumber = 0; for (auto& bin : in_bins) @@ -60,10 +66,12 @@ RecordTraversal::RecordTraversal(uint32_t in_maxSlot, std::set in_bins) : { _bins[bin->binNumber - _minimumBinNumber] = bin; } + } RecordTraversal::~RecordTraversal() { + SCOPED_INSTRUMENTASTION(instrumentation); } CommandBuffer* RecordTraversal::getCommandBuffer() @@ -91,6 +99,8 @@ void RecordTraversal::setDatabasePager(DatabasePager* dp) void RecordTraversal::clearBins() { + SCOPED_INSTRUMENTASTION(instrumentation); + for (auto& bin : _bins) { if (bin) bin->clear(); @@ -99,12 +109,16 @@ void RecordTraversal::clearBins() void RecordTraversal::apply(const Object& object) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("Visiting Object"); object.traverse(*this); } void RecordTraversal::apply(const Group& group) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("Visiting Group"); #if INLINE_TRAVERSE vsg::Group::t_traverse(group, *this); @@ -115,6 +129,8 @@ void RecordTraversal::apply(const Group& group) void RecordTraversal::apply(const QuadGroup& quadGroup) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("Visiting QuadGroup"); #if INLINE_TRAVERSE vsg::QuadGroup::t_traverse(quadGroup, *this); @@ -125,6 +141,8 @@ void RecordTraversal::apply(const QuadGroup& quadGroup) void RecordTraversal::apply(const LOD& lod) { + SCOPED_INSTRUMENTASTION(instrumentation); + const auto& sphere = lod.bound; // check if lod bounding sphere is in view frustum. @@ -148,6 +166,8 @@ void RecordTraversal::apply(const LOD& lod) void RecordTraversal::apply(const PagedLOD& plod) { + SCOPED_INSTRUMENTASTION(instrumentation); + const auto& sphere = plod.bound; auto frameCount = _frameStamp->frameCount; @@ -226,6 +246,8 @@ void RecordTraversal::apply(const PagedLOD& plod) void RecordTraversal::apply(const CullGroup& cullGroup) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (_state->intersect(cullGroup.bound)) { // debug("Passed node"); @@ -235,6 +257,8 @@ void RecordTraversal::apply(const CullGroup& cullGroup) void RecordTraversal::apply(const CullNode& cullNode) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (_state->intersect(cullNode.bound)) { //debug("Passed node"); @@ -244,6 +268,8 @@ void RecordTraversal::apply(const CullNode& cullNode) void RecordTraversal::apply(const DepthSorted& depthSorted) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (_state->intersect(depthSorted.bound)) { const auto& mv = _state->modelviewMatrixStack.top(); @@ -256,6 +282,8 @@ void RecordTraversal::apply(const DepthSorted& depthSorted) void RecordTraversal::apply(const Switch& sw) { + SCOPED_INSTRUMENTASTION(instrumentation); + for (auto& child : sw.children) { if ((traversalMask & (overrideMask | child.mask)) != MASK_OFF) @@ -267,35 +295,47 @@ void RecordTraversal::apply(const Switch& sw) void RecordTraversal::apply(const Light& /*light*/) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("RecordTraversal::apply(Light) ", light.className()); } void RecordTraversal::apply(const AmbientLight& light) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("RecordTraversal::apply(AmbientLight) ", light.className()); if (_viewDependentState) _viewDependentState->ambientLights.emplace_back(_state->modelviewMatrixStack.top(), &light); } void RecordTraversal::apply(const DirectionalLight& light) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("RecordTraversal::apply(DirectionalLight) ", light.className()); if (_viewDependentState) _viewDependentState->directionalLights.emplace_back(_state->modelviewMatrixStack.top(), &light); } void RecordTraversal::apply(const PointLight& light) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("RecordTraversal::apply(PointLight) ", light.className()); if (_viewDependentState) _viewDependentState->pointLights.emplace_back(_state->modelviewMatrixStack.top(), &light); } void RecordTraversal::apply(const SpotLight& light) { + SCOPED_INSTRUMENTASTION(instrumentation); + //debug("RecordTraversal::apply(SpotLight) ", light.className()); if (_viewDependentState) _viewDependentState->spotLights.emplace_back(_state->modelviewMatrixStack.top(), &light); } void RecordTraversal::apply(const StateGroup& stateGroup) { + SCOPED_INSTRUMENTASTION_C(instrumentation, ubvec4(255, 255, 0, 255)); + //debug("Visiting StateGroup"); for (auto& command : stateGroup.stateCommands) @@ -315,6 +355,8 @@ void RecordTraversal::apply(const StateGroup& stateGroup) void RecordTraversal::apply(const Transform& transform) { + SCOPED_INSTRUMENTASTION(instrumentation); + _state->modelviewMatrixStack.push(transform); _state->dirty = true; @@ -335,6 +377,8 @@ void RecordTraversal::apply(const Transform& transform) void RecordTraversal::apply(const MatrixTransform& mt) { + SCOPED_INSTRUMENTASTION(instrumentation); + _state->modelviewMatrixStack.push(mt); _state->dirty = true; @@ -356,6 +400,8 @@ void RecordTraversal::apply(const MatrixTransform& mt) // Vulkan nodes void RecordTraversal::apply(const Commands& commands) { + SCOPED_INSTRUMENTASTION_C(instrumentation, ubvec4(0, 255, 0, 255)); + _state->record(); for (auto& command : commands.children) { @@ -365,6 +411,8 @@ void RecordTraversal::apply(const Commands& commands) void RecordTraversal::apply(const Command& command) { + SCOPED_INSTRUMENTASTION_C(instrumentation, ubvec4(0, 255, 0, 255)); + //debug("Visiting Command"); _state->record(); command.record(*(_state->_commandBuffer)); @@ -372,6 +420,8 @@ void RecordTraversal::apply(const Command& command) void RecordTraversal::apply(const View& view) { + SCOPED_INSTRUMENTASTION_C(instrumentation, ubvec4(0, 0, 255, 255)); + // note, View::accept() updates the RecordTraversal's traversalMask auto cached_traversalMask = _state->_commandBuffer->traversalMask; _state->_commandBuffer->traversalMask = traversalMask; @@ -459,6 +509,8 @@ void RecordTraversal::apply(const View& view) void RecordTraversal::apply(const CommandGraph& commandGraph) { + SCOPED_INSTRUMENTASTION_C(instrumentation, ubvec4(0, 0, 255, 255)); + if (recordedCommandBuffers) { auto cg = const_cast(&commandGraph); diff --git a/src/vsg/app/Viewer.cpp b/src/vsg/app/Viewer.cpp index 987e7527ad..83735abfa6 100644 --- a/src/vsg/app/Viewer.cpp +++ b/src/vsg/app/Viewer.cpp @@ -16,6 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include #include @@ -32,10 +33,13 @@ Viewer::Viewer() : status(vsg::ActivityStatus::create()), _start_point(clock::now()) { + SCOPED_INSTRUMENTASTION(instrumentation); } Viewer::~Viewer() { + SCOPED_INSTRUMENTASTION(instrumentation); + stopThreading(); // don't destroy viewer while devices are still active @@ -44,6 +48,8 @@ Viewer::~Viewer() void Viewer::deviceWaitIdle() const { + SCOPED_INSTRUMENTASTION(instrumentation); + std::set devices; for (auto& window : _windows) { @@ -96,6 +102,8 @@ void Viewer::removeWindow(ref_ptr window) void Viewer::close() { + SCOPED_INSTRUMENTASTION(instrumentation); + _close = true; status->set(false); @@ -104,6 +112,8 @@ void Viewer::close() bool Viewer::active() const { + SCOPED_INSTRUMENTASTION(instrumentation); + bool viewerIsActive = !_close; if (viewerIsActive) { @@ -127,6 +137,8 @@ bool Viewer::active() const bool Viewer::pollEvents(bool discardPreviousEvents) { + SCOPED_INSTRUMENTASTION(instrumentation); + bool result = false; if (discardPreviousEvents) _events.clear(); @@ -140,6 +152,8 @@ bool Viewer::pollEvents(bool discardPreviousEvents) bool Viewer::advanceToNextFrame() { + SCOPED_INSTRUMENTASTION(instrumentation); + if (!active()) return false; // poll all the windows for events. @@ -178,6 +192,8 @@ bool Viewer::advanceToNextFrame() bool Viewer::acquireNextFrame() { + SCOPED_INSTRUMENTASTION(instrumentation); + if (_close) return false; VkResult result = VK_SUCCESS; @@ -216,6 +232,8 @@ bool Viewer::acquireNextFrame() VkResult Viewer::waitForFences(size_t relativeFrameIndex, uint64_t timeout) { + SCOPED_INSTRUMENTASTION(instrumentation); + VkResult result = VK_SUCCESS; for (auto& task : recordAndSubmitTasks) { @@ -231,6 +249,8 @@ VkResult Viewer::waitForFences(size_t relativeFrameIndex, uint64_t timeout) void Viewer::handleEvents() { + SCOPED_INSTRUMENTASTION(instrumentation); + for (auto& vsg_event : _events) { for (auto& handler : _eventHandlers) @@ -242,6 +262,8 @@ void Viewer::handleEvents() void Viewer::compile(ref_ptr hints) { + SCOPED_INSTRUMENTASTION(instrumentation); + if (recordAndSubmitTasks.empty()) { return; @@ -399,6 +421,8 @@ void Viewer::compile(ref_ptr hints) void Viewer::assignRecordAndSubmitTaskAndPresentation(CommandGraphs in_commandGraphs) { + SCOPED_INSTRUMENTASTION(instrumentation); + // now remove any commandGraphs associated with window bool needToStartThreading = _threading; if (_threading) stopThreading(); @@ -554,6 +578,8 @@ void Viewer::assignRecordAndSubmitTaskAndPresentation(CommandGraphs in_commandGr void Viewer::addRecordAndSubmitTaskAndPresentation(CommandGraphs commandGraphs) { + SCOPED_INSTRUMENTASTION(instrumentation); + // collect the existing CommandGraphs CommandGraphs combinedCommandGraphs; for (auto& task : recordAndSubmitTasks) @@ -573,6 +599,8 @@ void Viewer::addRecordAndSubmitTaskAndPresentation(CommandGraphs commandGraphs) void Viewer::setupThreading() { + SCOPED_INSTRUMENTASTION(instrumentation); + debug("Viewer::setupThreading() "); stopThreading(); @@ -723,6 +751,8 @@ void Viewer::setupThreading() void Viewer::stopThreading() { + SCOPED_INSTRUMENTASTION(instrumentation); + if (!_threading) return; _threading = false; @@ -742,6 +772,8 @@ void Viewer::stopThreading() void Viewer::update() { + SCOPED_INSTRUMENTASTION(instrumentation); + for (auto& task : recordAndSubmitTasks) { if (task->databasePager) @@ -757,6 +789,8 @@ void Viewer::update() void Viewer::recordAndSubmit() { + SCOPED_INSTRUMENTASTION(instrumentation); + // reset connected ExecuteCommands for (auto& recordAndSubmitTask : recordAndSubmitTasks) { @@ -789,6 +823,8 @@ void Viewer::recordAndSubmit() void Viewer::present() { + SCOPED_INSTRUMENTASTION(instrumentation); + for (auto& presentation : presentations) { presentation->present(); @@ -797,5 +833,7 @@ void Viewer::present() void vsg::updateViewer(Viewer& viewer, const CompileResult& compileResult) { + SCOPED_INSTRUMENTASTION(viewer.instrumentation); + updateTasks(viewer.recordAndSubmitTasks, viewer.compileManager, compileResult); } diff --git a/src/vsg/app/WindowTraits.cpp b/src/vsg/app/WindowTraits.cpp index 9103cf49db..011c197074 100644 --- a/src/vsg/app/WindowTraits.cpp +++ b/src/vsg/app/WindowTraits.cpp @@ -105,7 +105,7 @@ void WindowTraits::validate() { instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } - if (debugUtils && isExtensionSupported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) + if ((apiDumpLayer || debugUtils) && isExtensionSupported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) { instanceExtensionNames.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } diff --git a/src/vsg/utils/Instrumentation.cpp b/src/vsg/utils/Instrumentation.cpp new file mode 100644 index 0000000000..72eaef528d --- /dev/null +++ b/src/vsg/utils/Instrumentation.cpp @@ -0,0 +1,69 @@ +/* + +Copyright(c) 2023 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +using namespace vsg; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Instrumentation base class +// +Instrumentation::Instrumentation() +{ +} + +Instrumentation::~Instrumentation() +{ +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// VulkanAnnotation uses VK_debug_utils to pass annotation to Vulkan +// +VulkanAnnotation::VulkanAnnotation() +{ +} + +VulkanAnnotation::~VulkanAnnotation() +{ +} + + +void VulkanAnnotation::enter(const SourceLocation* sl, uint64_t&) const +{ + if (!commandBuffer) return; + + auto extensions = commandBuffer->getDevice()->getInstance()->getExtensions(); + + VkDebugUtilsLabelEXT markerInfo = {}; + markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + if (sl->name) markerInfo.pLabelName = sl->name; + else markerInfo.pLabelName = sl->function; + markerInfo.color[0] = static_cast(sl->color[0])/255.0; + markerInfo.color[1] = static_cast(sl->color[1])/255.0; + markerInfo.color[2] = static_cast(sl->color[2])/255.0; + markerInfo.color[3] = static_cast(sl->color[3])/255.0; + + extensions->vkCmdBeginDebugUtilsLabelEXT(*commandBuffer, &markerInfo); +} + +void VulkanAnnotation::leave(const SourceLocation*, uint64_t&) const +{ + if (!commandBuffer) return; + + auto extensions = commandBuffer->getDevice()->getInstance()->getExtensions(); + extensions->vkCmdEndDebugUtilsLabelEXT(*commandBuffer); +}