From 38cd78e5f5f8d1504db74c2f4d81d43dc2b45b6f Mon Sep 17 00:00:00 2001 From: kunitoki Date: Thu, 19 Dec 2024 17:53:01 +0100 Subject: [PATCH 1/5] Forgot one method --- modules/juce_core/memory/juce_ReferenceCountedObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/juce_core/memory/juce_ReferenceCountedObject.h b/modules/juce_core/memory/juce_ReferenceCountedObject.h index 5aa91438..03b94fcd 100644 --- a/modules/juce_core/memory/juce_ReferenceCountedObject.h +++ b/modules/juce_core/memory/juce_ReferenceCountedObject.h @@ -144,7 +144,7 @@ class JUCE_API ReferenceCountedObject /** Resets the reference count to zero without deleting the object. You should probably never need to use this! */ - void resetReferenceCount() noexcept + void resetReferenceCount() const noexcept { refCount = 0; } From ff52eac6ae5dcdfe4f59e6a81951bfc275b8f5f0 Mon Sep 17 00:00:00 2001 From: kunitoki Date: Thu, 19 Dec 2024 23:29:42 +0100 Subject: [PATCH 2/5] More tweaks --- .clang-format | 2 +- examples/render/source/main.cpp | 12 +- .../native/juce_MessageQueue_apple.h | 14 +- .../native/yup_GraphicsContext_metal.cpp | 2 +- modules/yup_gui/artboard/yup_Artboard.cpp | 13 +- modules/yup_gui/artboard/yup_Artboard.h | 2 + .../yup_gui/component/yup_ComponentNative.h | 7 + modules/yup_gui/native/yup_Windowing_sdl2.cpp | 163 +++++++++--------- thirdparty/rive_decoders/rive_decoders.h | 10 +- 9 files changed, 122 insertions(+), 103 deletions(-) diff --git a/.clang-format b/.clang-format index fb599370..2611d9dd 100644 --- a/.clang-format +++ b/.clang-format @@ -42,7 +42,7 @@ IndentWidth: 4 IndentWrappedFunctionNames: true IndentPPDirectives: BeforeHash KeepEmptyLinesAtTheStartOfBlocks: false -LambdaBodyIndentation: Signature +LambdaBodyIndentation: OuterScope MaxEmptyLinesToKeep: 1 NamespaceIndentation: None PackConstructorInitializers: Never diff --git a/examples/render/source/main.cpp b/examples/render/source/main.cpp index 37ab0a65..6ee4f0ef 100644 --- a/examples/render/source/main.cpp +++ b/examples/render/source/main.cpp @@ -221,10 +221,10 @@ struct Application : yup::YUPApplication window->setVisible (true); window->toFront(); - window2 = std::make_unique(); - window2->centreWithSize ({ 300, 300 }); - window2->setVisible (true); - window2->toFront(); + //window2 = std::make_unique(); + //window2->centreWithSize ({ 300, 300 }); + //window2->setVisible (true); + //window2->toFront(); } void shutdown() override @@ -233,14 +233,14 @@ struct Application : yup::YUPApplication window.reset(); - window2.reset(); + //window2.reset(); YUP_PROFILE_STOP(); } private: std::unique_ptr window; - std::unique_ptr window2; + //std::unique_ptr window2; }; START_JUCE_APPLICATION (Application) diff --git a/modules/juce_events/native/juce_MessageQueue_apple.h b/modules/juce_events/native/juce_MessageQueue_apple.h index a1a2f57e..903e4dcd 100644 --- a/modules/juce_events/native/juce_MessageQueue_apple.h +++ b/modules/juce_events/native/juce_MessageQueue_apple.h @@ -110,21 +110,13 @@ class InternalMessageQueue { YUP_PROFILE_INTERNAL_TRACE(); - auto timeoutDetector = TimeoutDetector (1.0 / 60.0); - if (! deliverNextMessage()) return; - if (! timeoutDetector.hasTimedOut()) + for (int i = 3; --i >= 0;) { - for (int i = 3; --i >= 0;) - { - if (! deliverNextMessage()) - break; - - if (timeoutDetector.hasTimedOut()) - break; - } + if (! deliverNextMessage()) + break; } wakeUp(); diff --git a/modules/yup_graphics/native/yup_GraphicsContext_metal.cpp b/modules/yup_graphics/native/yup_GraphicsContext_metal.cpp index 19fe8617..34e0490f 100644 --- a/modules/yup_graphics/native/yup_GraphicsContext_metal.cpp +++ b/modules/yup_graphics/native/yup_GraphicsContext_metal.cpp @@ -78,7 +78,7 @@ class LowLevelRenderContextMetal : public GraphicsContext m_swapchain.contentsScale = dpiScale (window); m_swapchain.maximumDrawableCount = 2; #if ! TARGET_OS_IOS - m_swapchain.displaySyncEnabled = YES; + m_swapchain.displaySyncEnabled = NO; #endif #if TARGET_OS_IOS diff --git a/modules/yup_gui/artboard/yup_Artboard.cpp b/modules/yup_gui/artboard/yup_Artboard.cpp index f5d18399..d46bdd7e 100644 --- a/modules/yup_gui/artboard/yup_Artboard.cpp +++ b/modules/yup_gui/artboard/yup_Artboard.cpp @@ -110,14 +110,19 @@ void Artboard::setNumberInput (const String& name, double value) //============================================================================== +void Artboard::refreshDisplay (double lastFrameTimeSeconds) +{ + if (! paused) + advanceAndApply (static_cast (lastFrameTimeSeconds)); +} + +//============================================================================== + void Artboard::paint (Graphics& g) { - if (rivFile == nullptr || scene == nullptr) + if (scene == nullptr) return; - if (! paused && getNativeComponent() != nullptr) - scene->advanceAndApply (1.0f / getNativeComponent()->getDesiredFrameRate()); - auto* renderer = g.getRenderer(); renderer->save(); diff --git a/modules/yup_gui/artboard/yup_Artboard.h b/modules/yup_gui/artboard/yup_Artboard.h index 0b27c69c..9508ccb9 100644 --- a/modules/yup_gui/artboard/yup_Artboard.h +++ b/modules/yup_gui/artboard/yup_Artboard.h @@ -47,6 +47,7 @@ class JUCE_API Artboard : public Component virtual void propertyChanged (const String& eventName, const String& propertyName, const var& oldValue, const var& newValue); //============================================================================== + void refreshDisplay (double lastFrameTimeSeconds) override; void paint (Graphics& g) override; void resized() override; void mouseEnter (const MouseEvent& event) override; @@ -71,6 +72,7 @@ class JUCE_API Artboard : public Component int artboardIndex = -1; int animationIndex = -1; int stateMachineIndex = -1; + float animationTime = 0.0f; bool useStateMachines = true; bool paused = false; diff --git a/modules/yup_gui/component/yup_ComponentNative.h b/modules/yup_gui/component/yup_ComponentNative.h index dd404ecb..ca1b4623 100644 --- a/modules/yup_gui/component/yup_ComponentNative.h +++ b/modules/yup_gui/component/yup_ComponentNative.h @@ -107,11 +107,18 @@ class JUCE_API ComponentNative return *this; } + Options& withUpdateOnlyFocused (bool onlyWhenFocused) noexcept + { + updateOnlyWhenFocused = onlyWhenFocused; + return *this; + } + Flags flags = defaultFlags; ///< std::optional graphicsApi; ///< std::optional framerateRedraw; ///< std::optional clearColor; ///< std::optional doubleClickTime; ///< + bool updateOnlyWhenFocused = false; ///< }; //============================================================================== diff --git a/modules/yup_gui/native/yup_Windowing_sdl2.cpp b/modules/yup_gui/native/yup_Windowing_sdl2.cpp index 118ff1fe..dd990233 100644 --- a/modules/yup_gui/native/yup_Windowing_sdl2.cpp +++ b/modules/yup_gui/native/yup_Windowing_sdl2.cpp @@ -42,6 +42,12 @@ class SDL2ComponentNative final , public Thread , public AsyncUpdater { +#if (JUCE_EMSCRIPTEN && RIVE_WEBGL) && ! defined(__EMSCRIPTEN_PTHREADS__) + static constexpr bool renderDrivenByTimer = true; +#else + static constexpr bool renderDrivenByTimer = false; +#endif + public: //============================================================================== @@ -196,6 +202,8 @@ class SDL2ComponentNative final float desiredFrameRate = 60.0f; std::atomic currentFrameRate = 0.0f; + double frameRateStartTimeSeconds = 0.0; + uint64_t frameRateCounter = 0; int currentContentWidth = 0; int currentContentHeight = 0; @@ -205,6 +213,7 @@ class SDL2ComponentNative final double lastRenderTimeSeconds = 0.0; bool renderAtomicMode = false; bool renderWireframe = false; + bool updateOnlyWhenFocused = false; Rectangle currentRepaintArea; }; @@ -227,6 +236,7 @@ SDL2ComponentNative::SDL2ComponentNative (Component& component, , doubleClickTime (options.doubleClickTime.value_or (RelativeTime::milliseconds (200))) , desiredFrameRate (options.framerateRedraw.value_or (60.0f)) , shouldRenderContinuous (options.flags.test (renderContinuous)) + , updateOnlyWhenFocused (options.updateOnlyWhenFocused) { SDL_AddEventWatch (eventDispatcher, this); @@ -302,9 +312,8 @@ SDL2ComponentNative::~SDL2ComponentNative() { SDL_SetWindowData (window, "self", nullptr); SDL_DestroyWindow (window); + window = nullptr; } - - window = nullptr; } //============================================================================== @@ -622,9 +631,6 @@ void SDL2ComponentNative::run() const double maxFrameTimeSeconds = 1.0 / static_cast (desiredFrameRate); const double maxFrameTimeMs = maxFrameTimeSeconds * 1000.0; - double fpsMeasureStartTimeSeconds = juce::Time::getMillisecondCounterHiRes() / 1000.0; - uint64_t frameCounter = 0; - while (! threadShouldExit()) { double frameStartTimeSeconds = juce::Time::getMillisecondCounterHiRes() / 1000.0; @@ -650,19 +656,6 @@ void SDL2ComponentNative::run() while (juce::Time::getMillisecondCounterHiRes() < waitUntilMs) Thread::sleep (0); } - - // Measure current framerate - ++frameCounter; - - const double timeSinceFpsMeasure = currentTimeSeconds - fpsMeasureStartTimeSeconds; - if (timeSinceFpsMeasure >= 1.0) - { - const double currentFps = static_cast (frameCounter) / timeSinceFpsMeasure; - currentFrameRate.store (currentFps, std::memory_order_relaxed); - - fpsMeasureStartTimeSeconds = currentTimeSeconds; - frameCounter = 0; - } } } @@ -715,9 +708,13 @@ void SDL2ComponentNative::renderContext() setPosition (nativeWindowPos.getTopLeft()); } - auto newElapsedTime = juce::Time::getMillisecondCounterHiRes(); - component.internalRefreshDisplay (newElapsedTime - lastRenderTimeSeconds); - lastRenderTimeSeconds = newElapsedTime; + auto currentTimeSeconds = juce::Time::getMillisecondCounterHiRes() / 1000.0; + + { + YUP_PROFILE_NAMED_INTERNAL_TRACE (RefreshDisplay); + + component.internalRefreshDisplay (currentTimeSeconds - lastRenderTimeSeconds); + } if (renderContinuous) repaint(); @@ -776,6 +773,19 @@ void SDL2ComponentNative::renderContext() if (window != nullptr && currentGraphicsApi == GraphicsContext::OpenGL) SDL_GL_SwapWindow (window); + // Compute framerate + ++frameRateCounter; + + const double timeSinceFpsMeasure = currentTimeSeconds - frameRateStartTimeSeconds; + if (timeSinceFpsMeasure >= 1.0) + { + const double currentFps = static_cast (frameRateCounter) / timeSinceFpsMeasure; + currentFrameRate.store (currentFps, std::memory_order_relaxed); + + frameRateStartTimeSeconds = currentTimeSeconds; + frameRateCounter = 0; + } + currentRepaintArea = {}; } @@ -783,42 +793,49 @@ void SDL2ComponentNative::renderContext() void SDL2ComponentNative::startRendering() { - lastRenderTimeSeconds = juce::Time::getMillisecondCounterHiRes(); + lastRenderTimeSeconds = juce::Time::getMillisecondCounterHiRes() / 1000.0; + frameRateStartTimeSeconds = lastRenderTimeSeconds; + frameRateCounter = 0; -#if (JUCE_EMSCRIPTEN && RIVE_WEBGL) && ! defined(__EMSCRIPTEN_PTHREADS__) - if (! isTimerRunning()) - startTimerHz (desiredFrameRate); -#else - if (! isThreadRunning()) - startThread (Priority::high); -#endif + if constexpr (renderDrivenByTimer) + { + if (! isTimerRunning()) + startTimerHz (desiredFrameRate); + } + else + { + if (! isThreadRunning()) + startThread (Priority::high); + } repaint(); } void SDL2ComponentNative::stopRendering() { -#if (JUCE_EMSCRIPTEN && RIVE_WEBGL) && ! defined(__EMSCRIPTEN_PTHREADS__) - if (isTimerRunning()) - stopTimer(); -#else - if (isThreadRunning()) + if constexpr (renderDrivenByTimer) { - signalThreadShouldExit(); - notify(); - renderEvent.signal(); - stopThread (-1); + if (isTimerRunning()) + stopTimer(); + } + else + { + if (isThreadRunning()) + { + signalThreadShouldExit(); + notify(); + renderEvent.signal(); + stopThread (-1); + } } -#endif } bool SDL2ComponentNative::isRendering() const { -#if (JUCE_EMSCRIPTEN && RIVE_WEBGL) && ! defined(__EMSCRIPTEN_PTHREADS__) - return isTimerRunning(); -#else - return isThreadRunning(); -#endif + if constexpr (renderDrivenByTimer) + return isTimerRunning(); + else + return isThreadRunning(); } //============================================================================== @@ -991,8 +1008,6 @@ void SDL2ComponentNative::handleKeyUp (const KeyPress& keys, const Point& void SDL2ComponentNative::handleTextInput (const String& textInput) { - DBG ("handleTextInput: " << textInput); - if (lastComponentFocused != nullptr) lastComponentFocused->internalTextInput (textInput); else @@ -1003,8 +1018,6 @@ void SDL2ComponentNative::handleTextInput (const String& textInput) void SDL2ComponentNative::handleMoved (int xpos, int ypos) { - YUP_PROFILE_INTERNAL_TRACE(); - component.internalMoved (xpos, ypos); screenBounds = screenBounds.withPosition (xpos, ypos); @@ -1012,8 +1025,6 @@ void SDL2ComponentNative::handleMoved (int xpos, int ypos) void SDL2ComponentNative::handleResized (int width, int height) { - YUP_PROFILE_INTERNAL_TRACE(); - component.internalResized (width, height); screenBounds = screenBounds.withSize (width, height); @@ -1028,6 +1039,11 @@ void SDL2ComponentNative::handleFocusChanged (bool gotFocus) { startRendering(); } + else + { + if (updateOnlyWhenFocused) + stopRendering(); + } } void SDL2ComponentNative::handleMinimized() @@ -1042,13 +1058,11 @@ void SDL2ComponentNative::handleMaximized() void SDL2ComponentNative::handleRestored() { - startRendering(); + repaint(); } void SDL2ComponentNative::handleExposed() { - YUP_PROFILE_INTERNAL_TRACE(); - repaint(); } @@ -1372,16 +1386,16 @@ void Desktop::updateDisplays() void initialiseYup_Windowing() { - SDL_SetMainReady(); - // Initialise SDL + SDL_SetMainReady(); if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { DBG ("Error initialising SDL: " << SDL_GetError()); jassertfalse; - JUCEApplicationBase::quit(); + + return; } // Update available displays @@ -1390,32 +1404,25 @@ void initialiseYup_Windowing() // Inject the event loop MessageManager::getInstance()->registerEventLoopCallback ([] - { - constexpr double timeoutInterval = 1.0 / 60.0; - - YUP_PROFILE_NAMED_INTERNAL_TRACE (EventLoop); - - bool timeoutProcessingEvents = false; - auto timeoutDetector = TimeoutDetector (timeoutInterval); + { + YUP_PROFILE_NAMED_INTERNAL_TRACE (EventLoop); - SDL_Event event; - while (SDL_PollEvent (&event)) - { - YUP_PROFILE_NAMED_INTERNAL_TRACE (PollEvent); + constexpr double timeoutInterval = 1.0 / 60.0; // TODO + auto timeoutDetector = TimeoutDetector (timeoutInterval); - if (MessageManager::getInstance()->hasStopMessageBeenSent()) - return; + SDL_Event event; + while (SDL_PollEvent (&event)) + { + if (MessageManager::getInstance()->hasStopMessageBeenSent()) + break; - if (timeoutDetector.hasTimedOut()) - { - timeoutProcessingEvents = true; - break; - } - } + if (timeoutDetector.hasTimedOut()) + break; + } - if (! timeoutProcessingEvents) - SDL_Delay (1); - }); + if (! timeoutDetector.hasTimedOut()) + Thread::sleep (1); + }); SDL2ComponentNative::isInitialised.test_and_set(); } diff --git a/thirdparty/rive_decoders/rive_decoders.h b/thirdparty/rive_decoders/rive_decoders.h index 1be68498..48ae1ed3 100644 --- a/thirdparty/rive_decoders/rive_decoders.h +++ b/thirdparty/rive_decoders/rive_decoders.h @@ -32,9 +32,7 @@ website: https://github.com/rive-app/rive-runtime license: MIT - dependencies: libpng searchpaths: include - defines: RIVE_PNG=1 enableARC: 1 END_JUCE_MODULE_DECLARATION @@ -44,4 +42,12 @@ #pragma once +#if JUCE_MODULE_AVAILABLE_libpng +#define RIVE_PNG 1 +#endif + +#if JUCE_MODULE_AVAILABLE_libwebp +#define RIVE_WEBP 1 +#endif + #include "include/rive/decoders/bitmap_decoder.hpp" From d1413688c342864ad2e2ad7ffd47fbdaf8790d92 Mon Sep 17 00:00:00 2001 From: kunitoki Date: Thu, 19 Dec 2024 23:43:19 +0100 Subject: [PATCH 3/5] Record the profilation in a file descriptor --- modules/juce_core/profiling/juce_Profiler.cpp | 48 +++++++------------ modules/juce_core/profiling/juce_Profiler.h | 1 + 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/modules/juce_core/profiling/juce_Profiler.cpp b/modules/juce_core/profiling/juce_Profiler.cpp index 10cfeefc..2a668842 100644 --- a/modules/juce_core/profiling/juce_Profiler.cpp +++ b/modules/juce_core/profiling/juce_Profiler.cpp @@ -77,26 +77,10 @@ void Profiler::startTracing (uint32 sizeInKilobytes) { perfetto::TraceConfig traceConfig; traceConfig.add_buffers()->set_size_kb (sizeInKilobytes); + auto dataSourceConfig = traceConfig.add_data_sources()->mutable_config(); dataSourceConfig->set_name ("track_event"); - session = perfetto::Tracing::NewTrace(); - session->Setup (traceConfig); - session->StartBlocking(); -} - -//============================================================================== - -void Profiler::stopTracing() -{ - if (session == nullptr) - return; - - perfetto::TrackEvent::Flush(); - - session->StopBlocking(); - std::vector traceData (session->ReadTraceBlocking()); - String fileName; fileName << "yup-profile" @@ -114,23 +98,25 @@ void Profiler::stopTracing() if (destination.existsAsFile()) destination.deleteFile(); - if (auto output = destination.createOutputStream(); output != nullptr && output->openedOk()) - { - output->write (traceData.data(), traceData.size()); + fileDescriptor = open (destination.getFullPathName().toRawUTF8(), O_RDWR | O_CREAT | O_TRUNC, 0600); + + session = perfetto::Tracing::NewTrace(); + session->Setup (traceConfig, fileDescriptor); + session->StartBlocking(); +} + +//============================================================================== + +void Profiler::stopTracing() +{ + if (session == nullptr) + return; - String message; - message - << "Trace written in " << destination.getFullPathName() << ". " - << "To read this trace in text form, `./tools/traceconv text " << destination.getFullPathName() << "`"; + perfetto::TrackEvent::Flush(); - DBG (message); - } - else - { - DBG ("Failed to write trace file. Check for missing permissions."); + session->StopBlocking(); - jassertfalse; - } + close (fileDescriptor); Profiler::deleteInstance(); } diff --git a/modules/juce_core/profiling/juce_Profiler.h b/modules/juce_core/profiling/juce_Profiler.h index fa00b763..a1bd855c 100644 --- a/modules/juce_core/profiling/juce_Profiler.h +++ b/modules/juce_core/profiling/juce_Profiler.h @@ -84,6 +84,7 @@ class JUCE_API Profiler Profiler(); std::unique_ptr session; + int fileDescriptor; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Profiler); }; From 4cc8566856389c7de94916e9effe2f69ee26276b Mon Sep 17 00:00:00 2001 From: kunitoki Date: Fri, 20 Dec 2024 09:53:33 +0100 Subject: [PATCH 4/5] More improvements --- modules/yup_gui/native/yup_Windowing_sdl2.cpp | 200 +---------------- modules/yup_gui/native/yup_Windowing_sdl2.h | 208 ++++++++++++++++++ modules/yup_gui/yup_gui.cpp | 1 + 3 files changed, 211 insertions(+), 198 deletions(-) create mode 100644 modules/yup_gui/native/yup_Windowing_sdl2.h diff --git a/modules/yup_gui/native/yup_Windowing_sdl2.cpp b/modules/yup_gui/native/yup_Windowing_sdl2.cpp index dd990233..72f56c30 100644 --- a/modules/yup_gui/native/yup_Windowing_sdl2.cpp +++ b/modules/yup_gui/native/yup_Windowing_sdl2.cpp @@ -22,202 +22,6 @@ namespace yup { -//============================================================================== -#define YUP_VERBOSE_WINDOWING_DBG 1 - -#if YUP_VERBOSE_WINDOWING_DBG -#define YUP_DBG_WINDOWING(textToWrite) JUCE_BLOCK_WITH_FORCED_SEMICOLON ( \ - juce::String tempDbgBuf; \ - tempDbgBuf << textToWrite; \ - juce::Logger::outputDebugString (tempDbgBuf);) -#else -#define YUP_DBG_WINDOWING(textToWrite) -#endif - -//============================================================================== - -class SDL2ComponentNative final - : public ComponentNative - , public Timer - , public Thread - , public AsyncUpdater -{ -#if (JUCE_EMSCRIPTEN && RIVE_WEBGL) && ! defined(__EMSCRIPTEN_PTHREADS__) - static constexpr bool renderDrivenByTimer = true; -#else - static constexpr bool renderDrivenByTimer = false; -#endif - -public: - //============================================================================== - - SDL2ComponentNative (Component& component, - const Options& options, - void* parent); - - ~SDL2ComponentNative() override; - - //============================================================================== - - void setTitle (const String& title) override; - String getTitle() const override; - - //============================================================================== - - void setVisible (bool shouldBeVisible) override; - bool isVisible() const override; - - //============================================================================== - - void setSize (const Size& size) override; - Size getSize() const override; - Size getContentSize() const override; - - Point getPosition() const override; - void setPosition (const Point& newPosition) override; - - Rectangle getBounds() const override; - void setBounds (const Rectangle& newBounds) override; - - //============================================================================== - - void setFullScreen (bool shouldBeFullScreen) override; - bool isFullScreen() const override; - - //============================================================================== - - bool isDecorated() const override; - - //============================================================================== - bool isContinuousRepaintingEnabled() const override; - void enableContinuousRepainting (bool shouldBeEnabled) override; - bool isAtomicModeEnabled() const override; - void enableAtomicMode (bool shouldBeEnabled) override; - bool isWireframeEnabled() const override; - void enableWireframe (bool shouldBeEnabled) override; - - //============================================================================== - void repaint() override; - void repaint (const Rectangle& rect) override; - Rectangle getRepaintArea() const override; - - //============================================================================== - - float getScaleDpi() const override; - float getCurrentFrameRate() const override; - float getDesiredFrameRate() const override; - - //============================================================================== - - void setOpacity (float opacity) override; - float getOpacity() const override; - - //============================================================================== - - void setFocusedComponent (Component* comp) override; - Component* getFocusedComponent() const override; - - //============================================================================== - - rive::Factory* getFactory() override; - - //============================================================================== - - void* getNativeHandle() const override; - - //============================================================================== - - void run() override; - void handleAsyncUpdate() override; - void timerCallback() override; - - //============================================================================== - Point getCursorPosition() const; - - //============================================================================== - void handleMouseMoveOrDrag (const Point& localPosition); - void handleMouseDown (const Point& localPosition, MouseEvent::Buttons button, KeyModifiers modifiers); - void handleMouseUp (const Point& localPosition, MouseEvent::Buttons button, KeyModifiers modifiers); - void handleMouseWheel (const Point& localPosition, const MouseWheelData& wheelData); - void handleKeyDown (const KeyPress& keys, const Point& position); - void handleKeyUp (const KeyPress& keys, const Point& position); - void handleTextInput (const String& textInput); - void handleMoved (int xpos, int ypos); - void handleResized (int width, int height); - void handleFocusChanged (bool gotFocus); - void handleMinimized(); - void handleMaximized(); - void handleRestored(); - void handleExposed(); - void handleContentScaleChanged(); - void handleUserTriedToCloseWindow(); - - //============================================================================== - void handleWindowEvent (const SDL_WindowEvent& windowEvent); - - //============================================================================== - void handleEvent (SDL_Event* event); - static int eventDispatcher (void* userdata, SDL_Event* event); - - //============================================================================== - static std::atomic_flag isInitialised; - -private: - void updateComponentUnderMouse (const MouseEvent& event); - void renderContext(); - - void startRendering(); - void stopRendering(); - bool isRendering() const; - - SDL_Window* window = nullptr; - SDL_GLContext windowContext = nullptr; - - void* parentWindow = nullptr; - String windowTitle; - uint32 windowFlags = 0; - - GraphicsContext::Api currentGraphicsApi; - - std::unique_ptr context; - std::unique_ptr renderer; - - Color clearColor; - float currentScaleDpi = 1.0f; - Rectangle screenBounds = { 0, 0, 1, 1 }; - Rectangle lastScreenBounds = { 0, 0, 1, 1 }; - Point lastMouseMovePosition = { -1.0f, -1.0f }; - std::optional> lastMouseDownPosition; - std::optional lastMouseDownTime; - - WeakReference lastComponentClicked; - WeakReference lastComponentFocused; - WeakReference lastComponentUnderMouse; - - HashMap keyState; - MouseEvent::Buttons currentMouseButtons = MouseEvent::noButtons; - KeyModifiers currentKeyModifiers; - - RelativeTime doubleClickTime; - - float desiredFrameRate = 60.0f; - std::atomic currentFrameRate = 0.0f; - double frameRateStartTimeSeconds = 0.0; - uint64_t frameRateCounter = 0; - - int currentContentWidth = 0; - int currentContentHeight = 0; - - WaitableEvent renderEvent { true }; - std::atomic shouldRenderContinuous = false; - double lastRenderTimeSeconds = 0.0; - bool renderAtomicMode = false; - bool renderWireframe = false; - bool updateOnlyWhenFocused = false; - - Rectangle currentRepaintArea; -}; - //============================================================================== std::atomic_flag SDL2ComponentNative::isInitialised = ATOMIC_FLAG_INIT; @@ -731,8 +535,8 @@ void SDL2ComponentNative::renderContext() : rive::gpu::LoadAction::preserveRenderTarget; rive::gpu::RenderContext::FrameDescriptor frameDescriptor; - frameDescriptor.renderTargetWidth = static_cast (contentWidth); - frameDescriptor.renderTargetHeight = static_cast (contentHeight); + frameDescriptor.renderTargetWidth = static_cast (currentContentWidth); + frameDescriptor.renderTargetHeight = static_cast (currentContentHeight); frameDescriptor.loadAction = loadAction; frameDescriptor.clearColor = clearColor.getARGB(); frameDescriptor.disableRasterOrdering = renderAtomicMode; diff --git a/modules/yup_gui/native/yup_Windowing_sdl2.h b/modules/yup_gui/native/yup_Windowing_sdl2.h new file mode 100644 index 00000000..79b38bc5 --- /dev/null +++ b/modules/yup_gui/native/yup_Windowing_sdl2.h @@ -0,0 +1,208 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace yup +{ + +//============================================================================== +#define YUP_VERBOSE_WINDOWING_DBG 1 + +#if YUP_VERBOSE_WINDOWING_DBG +#define YUP_DBG_WINDOWING(textToWrite) JUCE_BLOCK_WITH_FORCED_SEMICOLON ( \ + juce::String tempDbgBuf; \ + tempDbgBuf << textToWrite; \ + juce::Logger::outputDebugString (tempDbgBuf);) +#else +#define YUP_DBG_WINDOWING(textToWrite) +#endif + +//============================================================================== +class SDL2ComponentNative final + : public ComponentNative + , public Timer + , public Thread + , public AsyncUpdater +{ +#if (JUCE_EMSCRIPTEN && RIVE_WEBGL) && ! defined(__EMSCRIPTEN_PTHREADS__) + static constexpr bool renderDrivenByTimer = true; +#else + static constexpr bool renderDrivenByTimer = false; +#endif + +public: + //============================================================================== + SDL2ComponentNative (Component& component, + const Options& options, + void* parent); + + ~SDL2ComponentNative() override; + + //============================================================================== + void setTitle (const String& title) override; + String getTitle() const override; + + //============================================================================== + void setVisible (bool shouldBeVisible) override; + bool isVisible() const override; + + //============================================================================== + void setSize (const Size& size) override; + Size getSize() const override; + Size getContentSize() const override; + + Point getPosition() const override; + void setPosition (const Point& newPosition) override; + + Rectangle getBounds() const override; + void setBounds (const Rectangle& newBounds) override; + + //============================================================================== + void setFullScreen (bool shouldBeFullScreen) override; + bool isFullScreen() const override; + + //============================================================================== + bool isDecorated() const override; + + //============================================================================== + bool isContinuousRepaintingEnabled() const override; + void enableContinuousRepainting (bool shouldBeEnabled) override; + bool isAtomicModeEnabled() const override; + void enableAtomicMode (bool shouldBeEnabled) override; + bool isWireframeEnabled() const override; + void enableWireframe (bool shouldBeEnabled) override; + + //============================================================================== + void repaint() override; + void repaint (const Rectangle& rect) override; + Rectangle getRepaintArea() const override; + + //============================================================================== + float getScaleDpi() const override; + float getCurrentFrameRate() const override; + float getDesiredFrameRate() const override; + + //============================================================================== + void setOpacity (float opacity) override; + float getOpacity() const override; + + //============================================================================== + void setFocusedComponent (Component* comp) override; + Component* getFocusedComponent() const override; + + //============================================================================== + rive::Factory* getFactory() override; + + //============================================================================== + void* getNativeHandle() const override; + + //============================================================================== + void run() override; + void handleAsyncUpdate() override; + void timerCallback() override; + + //============================================================================== + Point getCursorPosition() const; + + //============================================================================== + void handleMouseMoveOrDrag (const Point& localPosition); + void handleMouseDown (const Point& localPosition, MouseEvent::Buttons button, KeyModifiers modifiers); + void handleMouseUp (const Point& localPosition, MouseEvent::Buttons button, KeyModifiers modifiers); + void handleMouseWheel (const Point& localPosition, const MouseWheelData& wheelData); + void handleKeyDown (const KeyPress& keys, const Point& position); + void handleKeyUp (const KeyPress& keys, const Point& position); + void handleTextInput (const String& textInput); + void handleMoved (int xpos, int ypos); + void handleResized (int width, int height); + void handleFocusChanged (bool gotFocus); + void handleMinimized(); + void handleMaximized(); + void handleRestored(); + void handleExposed(); + void handleContentScaleChanged(); + void handleUserTriedToCloseWindow(); + + //============================================================================== + void handleWindowEvent (const SDL_WindowEvent& windowEvent); + + //============================================================================== + void handleEvent (SDL_Event* event); + static int eventDispatcher (void* userdata, SDL_Event* event); + + //============================================================================== + static std::atomic_flag isInitialised; + +private: + void updateComponentUnderMouse (const MouseEvent& event); + void renderContext(); + + void startRendering(); + void stopRendering(); + bool isRendering() const; + + SDL_Window* window = nullptr; + SDL_GLContext windowContext = nullptr; + + void* parentWindow = nullptr; + String windowTitle; + uint32 windowFlags = 0; + + GraphicsContext::Api currentGraphicsApi; + + std::unique_ptr context; + std::unique_ptr renderer; + + Color clearColor; + float currentScaleDpi = 1.0f; + Rectangle screenBounds = { 0, 0, 1, 1 }; + Rectangle lastScreenBounds = { 0, 0, 1, 1 }; + Point lastMouseMovePosition = { -1.0f, -1.0f }; + std::optional> lastMouseDownPosition; + std::optional lastMouseDownTime; + + WeakReference lastComponentClicked; + WeakReference lastComponentFocused; + WeakReference lastComponentUnderMouse; + + HashMap keyState; + MouseEvent::Buttons currentMouseButtons = MouseEvent::noButtons; + KeyModifiers currentKeyModifiers; + + RelativeTime doubleClickTime; + + float desiredFrameRate = 60.0f; + std::atomic currentFrameRate = 0.0f; + double frameRateStartTimeSeconds = 0.0; + uint64_t frameRateCounter = 0; + + int currentContentWidth = 0; + int currentContentHeight = 0; + + WaitableEvent renderEvent { true }; + std::atomic shouldRenderContinuous = false; + double lastRenderTimeSeconds = 0.0; + bool renderAtomicMode = false; + bool renderWireframe = false; + bool updateOnlyWhenFocused = false; + + Rectangle currentRepaintArea; +}; + +} // namespace yup diff --git a/modules/yup_gui/yup_gui.cpp b/modules/yup_gui/yup_gui.cpp index de40463c..9ab68520 100644 --- a/modules/yup_gui/yup_gui.cpp +++ b/modules/yup_gui/yup_gui.cpp @@ -90,4 +90,5 @@ //============================================================================== #include "native/yup_Windowing_utils.h" +#include "native/yup_Windowing_sdl2.h" #include "native/yup_Windowing_sdl2.cpp" From 1f60a3f03641c209567398913b9cb859f89b4d2f Mon Sep 17 00:00:00 2001 From: kunitoki Date: Fri, 20 Dec 2024 11:16:10 +0100 Subject: [PATCH 5/5] Improved profiler --- modules/juce_core/juce_core.h | 7 +++++ modules/juce_core/profiling/juce_Profiler.cpp | 21 ++++++++++--- modules/juce_core/profiling/juce_Profiler.h | 30 +++++++++++++++---- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 5cabf80d..773eab30 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -202,6 +202,13 @@ #define JUCE_PROFILING_CATEGORIES #endif +/** Config: JUCE_PROFILING_FILE_PREFIX + If provided, it will be used as prefix for profilation files generated. By default it will use "yup-profile". +*/ +#ifndef JUCE_PROFILING_FILE_PREFIX +#define JUCE_PROFILING_FILE_PREFIX "yup-profile" +#endif + #ifndef JUCE_STRING_UTF_TYPE #define JUCE_STRING_UTF_TYPE 8 #endif diff --git a/modules/juce_core/profiling/juce_Profiler.cpp b/modules/juce_core/profiling/juce_Profiler.cpp index 2a668842..32233003 100644 --- a/modules/juce_core/profiling/juce_Profiler.cpp +++ b/modules/juce_core/profiling/juce_Profiler.cpp @@ -83,17 +83,23 @@ void Profiler::startTracing (uint32 sizeInKilobytes) String fileName; fileName - << "yup-profile" + << JUCE_PROFILING_FILE_PREFIX #if JUCE_DEBUG << "-DEBUG-" #else << "-RELEASE-" #endif - << Time::getCurrentTime().formatted ("%Y-%m-%d_%H%M%S") + << Time::getCurrentTime().formatted ("%Y%m%d%H%M%S") + << "-" << String::toHexString (static_cast (Random::getSystemRandom().nextInt())) << ".pftrace"; - const auto destination = File::getSpecialLocation (File::userHomeDirectory) // TODO - make it configurable - .getChildFile (fileName); + File destination; + if (outputFolder != File() && outputFolder.isDirectory()) + destination = outputFolder; + else + destination = File::getSpecialLocation (File::userHomeDirectory); + + destination = destination.getChildFile (fileName); if (destination.existsAsFile()) destination.deleteFile(); @@ -121,6 +127,13 @@ void Profiler::stopTracing() Profiler::deleteInstance(); } +//============================================================================== + +void Profiler::setOutputFolder (const File& newOutputFolder) +{ + outputFolder = newOutputFolder; +} + } // namespace juce #endif diff --git a/modules/juce_core/profiling/juce_Profiler.h b/modules/juce_core/profiling/juce_Profiler.h index a1bd855c..4abc659c 100644 --- a/modules/juce_core/profiling/juce_Profiler.h +++ b/modules/juce_core/profiling/juce_Profiler.h @@ -46,6 +46,8 @@ class JUCE_API Profiler This method starts the tracing process using a default buffer size. The tracing session is managed internally and will continue until `stopTracing()` is called. + + @see YUP_PROFILE_START */ void startTracing(); @@ -54,6 +56,8 @@ class JUCE_API Profiler This method allows you to specify the buffer size used for tracing. The buffer size is defined in kilobytes. @param sizeInKilobytes The size of the tracing buffer in kilobytes. + + @see YUP_PROFILE_START */ void startTracing (uint32 sizeInKilobytes); @@ -61,9 +65,21 @@ class JUCE_API Profiler This method stops the tracing process and finalizes the trace data. Once tracing is stopped, the data can be retrieved and analyzed. + + @see YUP_PROFILE_STOP */ void stopTracing(); + /** Define the output folder of the traces. + + Call this method as erly as possible to + + @param newOutputFolder The output folder where to save traces. + + @see YUP_PROFILE_SET_OUTPUT_FOLDER + */ + void setOutputFolder (const File& newOutputFolder); + /** A constexpr function that prettifies a function name at compile time. This template function accepts a function name and formats it in a more readable manner at compile time. @@ -84,6 +100,7 @@ class JUCE_API Profiler Profiler(); std::unique_ptr session; + File outputFolder; int fileDescriptor; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Profiler); @@ -154,6 +171,9 @@ constexpr auto Profiler::compileTimePrettierFunction (F func) */ #define YUP_PROFILE_STOP(...) ::juce::Profiler::getInstance()->stopTracing() +/** Define the output folder of the traces. */ +#define YUP_PROFILE_SET_OUTPUT_FOLDER(path) ::juce::Profiler::getInstance()->setOutputFolder (path) + #if ! YUP_PROFILE_DISABLE_TRACE /** Records a profiling trace event. @@ -168,7 +188,7 @@ constexpr auto Profiler::compileTimePrettierFunction (F func) constexpr auto JUCE_JOIN_MACRO (juce_pfn_, __LINE__) = ::juce::Profiler::compileTimePrettierFunction ([] { return PERFETTO_DEBUG_FUNCTION_IDENTIFIER(); }); \ TRACE_EVENT (category, ::perfetto::StaticString (JUCE_JOIN_MACRO (juce_pfn_, __LINE__).data()), ##__VA_ARGS__) -#define YUP_PROFILE_NAMED_TRACE(category, name, ...) \ +#define YUP_PROFILE_NAMED_TRACE(category, name, ...) \ TRACE_EVENT (category, ::perfetto::StaticString (#name), ##__VA_ARGS__) /** Records a profiling internal trace event. @@ -177,18 +197,18 @@ constexpr auto Profiler::compileTimePrettierFunction (F func) @param ... Optional additional arguments for the trace event. */ -#define YUP_PROFILE_INTERNAL_TRACE(...) \ +#define YUP_PROFILE_INTERNAL_TRACE(...) \ constexpr auto JUCE_JOIN_MACRO (juce_pfn_, __LINE__) = ::juce::Profiler::compileTimePrettierFunction ([] { return PERFETTO_DEBUG_FUNCTION_IDENTIFIER(); }); \ TRACE_EVENT ("yup", ::perfetto::StaticString (JUCE_JOIN_MACRO (juce_pfn_, __LINE__).data()), ##__VA_ARGS__) -#define YUP_PROFILE_NAMED_INTERNAL_TRACE(name, ...) \ +#define YUP_PROFILE_NAMED_INTERNAL_TRACE(name, ...) \ TRACE_EVENT ("yup", ::perfetto::StaticString (#name), ##__VA_ARGS__) #else #define YUP_PROFILE_TRACE(category, ...) -#define YUP_PROFILE_NAMED_TRACE(category, name, ...) \ +#define YUP_PROFILE_NAMED_TRACE(category, name, ...) #define YUP_PROFILE_INTERNAL_TRACE(...) -#define YUP_PROFILE_NAMED_INTERNAL_TRACE(name, ...) \ +#define YUP_PROFILE_NAMED_INTERNAL_TRACE(name, ...) #endif // clang-format on