From 4baeca16037bb37c66f2b7aa8cc93a4459c0d176 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Tue, 25 Nov 2025 23:29:48 +0100 Subject: [PATCH] better timing --- examples/HelloAnimation/main.cpp | 1 + implementations/Crafter.Graphics-Window.cpp | 15 ++++++ .../Crafter.Graphics-Window_wayland.cpp | 48 +++++++++++-------- interfaces/Crafter.Graphics-Window.cppm | 12 +++++ 4 files changed, 56 insertions(+), 20 deletions(-) diff --git a/examples/HelloAnimation/main.cpp b/examples/HelloAnimation/main.cpp index 75edede..c4865da 100644 --- a/examples/HelloAnimation/main.cpp +++ b/examples/HelloAnimation/main.cpp @@ -36,6 +36,7 @@ int main() { if(anim.currentFrame == anim.keyframes.size()-1) { anim.Start(time.now); } + window.LogTiming(); }); element.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}}; diff --git a/implementations/Crafter.Graphics-Window.cpp b/implementations/Crafter.Graphics-Window.cpp index b94e937..1c0f1b5 100644 --- a/implementations/Crafter.Graphics-Window.cpp +++ b/implementations/Crafter.Graphics-Window.cpp @@ -60,3 +60,18 @@ void Window::ScaleMouse(Transform& element) { // element.scaled.x = MappedToPixelBoundless(element.anchorX, boundlessWidth) - MappedToPixelBoundless(element.anchorOffsetX, element.scaled.width) + PixelToMappedBoundless(parent.scaled.x, width); // element.scaled.y = MappedToPixelBoundless(element.anchorY, boundlessHeight) - MappedToPixelBoundless(element.anchorOffsetY, element.scaled.height) + PixelToMappedBoundless(parent.scaled.y, height); } + +#ifdef CRAFTER_TIMING +void Window::LogTiming() { + std::cout << std::format("Update: {}", duration_cast(totalUpdate)) << std::endl; + for (const std::pair*, std::chrono::nanoseconds>& entry : updateTimings) { + std::cout << std::format("\t{} {}", reinterpret_cast(entry.first), duration_cast(entry.second)) << std::endl; + } + std::cout << std::format("Render: {}", duration_cast(totalRender)) << std::endl; + for (const std::tuple& entry : renderTimings) { + std::cout << std::format("\t{} {}x{} {}", reinterpret_cast(std::get<0>(entry)), std::get<1>(entry), std::get<2>(entry), duration_cast(std::get<3>(entry))) << std::endl; + } + std::cout << std::format("Vblank: {}", duration_cast(vblank)) << std::endl; + std::cout << std::format("Total: {}", duration_cast(totalUpdate+totalRender+vblank)) << std::endl; +} +#endif \ No newline at end of file diff --git a/implementations/Crafter.Graphics-Window_wayland.cpp b/implementations/Crafter.Graphics-Window_wayland.cpp index 762f3a5..0a2afb1 100644 --- a/implementations/Crafter.Graphics-Window_wayland.cpp +++ b/implementations/Crafter.Graphics-Window_wayland.cpp @@ -136,13 +136,16 @@ void WindowWayland::StartSync() { -void RenderElement(Transform* transform, WindowWayland* window) { +void WindowWayland::RenderElement(Transform* transform) { RenderingElement* element = dynamic_cast(transform); if(element) { + #ifdef CRAFTER_TIMING + auto start = std::chrono::high_resolution_clock::now(); + #endif for (std::int_fast32_t x = element->scaled.x; x - element->scaled.x < element->scaled.width; x++) { for (std::int_fast32_t y = element->scaled.y; y - element->scaled.y < element->scaled.height; y++) { - if (x >= 0 && x < window->width && y >= 0 && y < window->height) { - Pixel_BU8_GU8_RU8_AU8& dst = window->framebuffer[y * window->width + x]; + if (x >= 0 && x < width && y >= 0 && y < height) { + Pixel_BU8_GU8_RU8_AU8& dst = framebuffer[y * width + x]; const Pixel_BU8_GU8_RU8_AU8& src = element->bufferScaled[(y - element->scaled.y) * element->scaled.width + (x - element->scaled.x)]; float srcA = src.a / 255.0f; @@ -160,11 +163,15 @@ void RenderElement(Transform* transform, WindowWayland* window) { } } } + #ifdef CRAFTER_TIMING + auto end = std::chrono::high_resolution_clock::now(); + renderTimings.push_back({element, element->scaled.width, element->scaled.height, end-start}); + #endif } std::sort(transform->children.begin(), transform->children.end(), [](Transform* a, Transform* b){ return a->z < b->z; }); for(Transform* child : transform->children) { - RenderElement(child, window); + this->RenderElement(child); } } @@ -172,13 +179,13 @@ void WindowWayland::Render() { std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; }); for (std::uint_fast32_t x = 0; x < width; x++) { - for (std::uint_fast32_t y = 0; y - height; y++) { + for (std::uint_fast32_t y = 0; y < height; y++) { framebuffer[y * width + x] = {0,0,0,0}; } } for(Transform* child : elements) { - RenderElement(child, this); + RenderElement(child); } wl_surface_attach(surface, buffer, 0, 0); @@ -238,38 +245,39 @@ std::chrono::time_point framEnd; void WindowWayland::wl_surface_frame_done(void* data, struct wl_callback *cb, uint32_t time) { - #ifdef CRAFTER_TIMING auto start = std::chrono::high_resolution_clock::now(); - auto vblank = duration_cast(start - framEnd); - #endif wl_callback_destroy(cb); WindowWayland* window = reinterpret_cast(data); + #ifdef CRAFTER_TIMING + window->vblank = duration_cast(start - window->frameEnd); + #endif if(window->updating) { cb = wl_surface_frame(window->surface); wl_callback_add_listener(cb, &WindowWayland::wl_callback_listener, window); window->onUpdate.Invoke({start, start-window->lastFrameBegin}); #ifdef CRAFTER_TIMING - std::chrono::nanoseconds totalUpdate = std::chrono::nanoseconds(0); + window->totalUpdate = std::chrono::nanoseconds(0); + window->updateTimings.clear(); for (const std::pair*, std::chrono::nanoseconds>& entry : window->onUpdate.listenerTimes) { - totalUpdate += entry.second; + window->updateTimings.push_back(entry); + window->totalUpdate += entry.second; } - std::cout << std::format("Update: {}", duration_cast(totalUpdate)) << std::endl; - for (const std::pair*, std::chrono::nanoseconds>& entry : window->onUpdate.listenerTimes) { - std::cout << std::format("\t{} {}", reinterpret_cast(entry.first), entry.second) << std::endl; - } - auto startRender = std::chrono::high_resolution_clock::now(); + #endif + #ifdef CRAFTER_TIMING + auto renderStart = std::chrono::high_resolution_clock::now(); + window->renderTimings.clear(); #endif window->Render(); #ifdef CRAFTER_TIMING - auto endRender = std::chrono::high_resolution_clock::now(); - auto end = std::chrono::high_resolution_clock::now(); - std::cout << std::format("Render: {}, Vblank: {}, Total: {}", duration_cast(endRender - startRender), vblank, duration_cast(totalUpdate+(endRender - startRender)+vblank)) << std::endl; + auto renderEnd = std::chrono::high_resolution_clock::now(); + window->totalRender = renderEnd - renderStart; #endif + } #ifdef CRAFTER_TIMING - framEnd = std::chrono::high_resolution_clock::now(); + window->frameEnd = std::chrono::high_resolution_clock::now(); #endif window->lastFrameBegin = start; } diff --git a/interfaces/Crafter.Graphics-Window.cppm b/interfaces/Crafter.Graphics-Window.cppm index 97b7f5a..acfc4a9 100644 --- a/interfaces/Crafter.Graphics-Window.cppm +++ b/interfaces/Crafter.Graphics-Window.cppm @@ -45,6 +45,7 @@ import Crafter.Event; export namespace Crafter { class Transform; + class RenderingElement; class Window { public: std::uint_fast32_t width; @@ -68,6 +69,16 @@ export namespace Crafter { void ScaleElement(Transform& element); void ScaleMouse(Transform& element, Transform& parent); void ScaleMouse(Transform& element); + #ifdef CRAFTER_TIMING + std::chrono::nanoseconds totalUpdate; + std::vector*, std::chrono::nanoseconds>> updateTimings; + std::chrono::nanoseconds totalRender; + std::vector> renderTimings; + std::chrono::nanoseconds vblank; + std::chrono::nanoseconds totalFrame; + std::chrono::time_point frameEnd; + void LogTiming(); + #endif }; class WindowKeyboard { @@ -145,6 +156,7 @@ export namespace Crafter { xkb_keymap* xkb_keymap; xkb_context* xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); xkb_state* xkb_state; + void RenderElement(Transform* transform); void Render() override; void StartSync() override; void StartUpdate() override;