mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-02 12:26:00 +01:00
Added a debug overlay
This commit is contained in:
parent
9b6960eb55
commit
8c10857f14
7 changed files with 221 additions and 4 deletions
|
@ -192,6 +192,9 @@ void CCompositor::startCompositor() {
|
|||
Debug::log(LOG, "Creating the EventManager!");
|
||||
g_pEventManager = std::make_unique<CEventManager>();
|
||||
g_pEventManager->startThread();
|
||||
|
||||
Debug::log(LOG, "Creating the HyprDebugOverlay!");
|
||||
g_pDebugOverlay = std::make_unique<CHyprDebugOverlay>();
|
||||
//
|
||||
//
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "managers/KeybindManager.hpp"
|
||||
#include "managers/AnimationManager.hpp"
|
||||
#include "managers/EventManager.hpp"
|
||||
#include "debug/HyprDebugOverlay.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
#include "helpers/Workspace.hpp"
|
||||
#include "Window.hpp"
|
||||
|
|
|
@ -35,6 +35,7 @@ void CConfigManager::setDefaultVars() {
|
|||
|
||||
configValues["debug:int"].intValue = 0;
|
||||
configValues["debug:log_damage"].intValue = 0;
|
||||
configValues["debug:overlay"].intValue = 0;
|
||||
|
||||
configValues["decoration:rounding"].intValue = 1;
|
||||
configValues["decoration:blur"].intValue = 1;
|
||||
|
|
154
src/debug/HyprDebugOverlay.cpp
Normal file
154
src/debug/HyprDebugOverlay.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
#include "HyprDebugOverlay.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void CHyprMonitorDebugOverlay::renderData(SMonitor* pMonitor, float µs) {
|
||||
m_dLastRenderTimes.push_back(µs / 1000.f);
|
||||
|
||||
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
|
||||
m_dLastRenderTimes.pop_front();
|
||||
|
||||
if (!m_pMonitor)
|
||||
m_pMonitor = pMonitor;
|
||||
}
|
||||
|
||||
void CHyprMonitorDebugOverlay::frameData(SMonitor* pMonitor) {
|
||||
m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
|
||||
|
||||
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
|
||||
m_dLastFrametimes.pop_front();
|
||||
|
||||
m_tpLastFrame = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (!m_pMonitor)
|
||||
m_pMonitor = pMonitor;
|
||||
}
|
||||
|
||||
int CHyprMonitorDebugOverlay::draw(int offset) {
|
||||
|
||||
if (!m_pMonitor)
|
||||
return 0;
|
||||
|
||||
int yOffset = offset;
|
||||
cairo_text_extents_t cairoExtents;
|
||||
float maxX = 0;
|
||||
std::string text = "";
|
||||
|
||||
// get avg fps
|
||||
float avgFrametime = 0;
|
||||
for (auto& ft : m_dLastFrametimes) {
|
||||
avgFrametime += ft;
|
||||
}
|
||||
avgFrametime /= m_dLastFrametimes.size() == 0 ? 1 : m_dLastFrametimes.size();
|
||||
|
||||
float avgRenderTime = 0;
|
||||
for (auto& rt : m_dLastRenderTimes) {
|
||||
avgRenderTime += rt;
|
||||
}
|
||||
avgRenderTime /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size();
|
||||
|
||||
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
|
||||
const float idealFPS = m_dLastFrametimes.size();
|
||||
|
||||
cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
|
||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
yOffset += 10;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = m_pMonitor->szName;
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
||||
|
||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16);
|
||||
|
||||
if (FPS > idealFPS * 0.95f)
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f);
|
||||
else if (FPS > idealFPS * 0.8f)
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 0.2f, 1.f);
|
||||
else
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f);
|
||||
|
||||
yOffset += 17;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string(std::to_string((int)FPS) + " FPS");
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
||||
|
||||
cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10);
|
||||
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string("Avg Frametime: " + std::to_string((int)avgFrametime) + "." + std::to_string((int)(avgFrametime * 10.f) % 10) + "ms");
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
||||
|
||||
yOffset += 11;
|
||||
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
|
||||
text = std::string("Avg Rendertime: " + std::to_string((int)avgRenderTime) + "." + std::to_string((int)(avgRenderTime * 10.f) % 10) + "ms");
|
||||
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
|
||||
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
|
||||
if (cairoExtents.width > maxX) maxX = cairoExtents.width;
|
||||
|
||||
yOffset += 11;
|
||||
|
||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||
m_wbLastDrawnBox = {(int)g_pCompositor->m_lMonitors.front().vecPosition.x, (int)g_pCompositor->m_lMonitors.front().vecPosition.y + offset - 1, (int)maxX + 2, yOffset - offset + 2};
|
||||
g_pHyprRenderer->damageBox(&m_wbLastDrawnBox);
|
||||
|
||||
return yOffset - offset;
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::renderData(SMonitor* pMonitor, float µs) {
|
||||
m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs);
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::frameData(SMonitor* pMonitor) {
|
||||
m_mMonitorOverlays[pMonitor].frameData(pMonitor);
|
||||
}
|
||||
|
||||
void CHyprDebugOverlay::draw() {
|
||||
|
||||
const auto PMONITOR = &g_pCompositor->m_lMonitors.front();
|
||||
|
||||
if (!m_pCairoSurface || !m_pCairo) {
|
||||
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecSize.x, PMONITOR->vecSize.y);
|
||||
m_pCairo = cairo_create(m_pCairoSurface);
|
||||
}
|
||||
|
||||
// clear the pixmap
|
||||
cairo_save(m_pCairo);
|
||||
cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint(m_pCairo);
|
||||
cairo_restore(m_pCairo);
|
||||
|
||||
// draw the things
|
||||
int offsetY = 0;
|
||||
for (auto& m : g_pCompositor->m_lMonitors) {
|
||||
offsetY += m_mMonitorOverlays[&m].draw(offsetY);
|
||||
offsetY += 5; // for padding between mons
|
||||
}
|
||||
|
||||
cairo_surface_flush(m_pCairoSurface);
|
||||
|
||||
// copy the data to an OpenGL texture we have
|
||||
const auto DATA = cairo_image_surface_get_data(m_pCairoSurface);
|
||||
m_tTexture.allocate();
|
||||
glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
#ifndef GLES2
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecSize.x, PMONITOR->vecSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
|
||||
wlr_box pMonBox = {0,0,PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
||||
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 255.f);
|
||||
}
|
44
src/debug/HyprDebugOverlay.hpp
Normal file
44
src/debug/HyprDebugOverlay.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../render/Texture.hpp"
|
||||
#include <deque>
|
||||
#include <cairo/cairo.h>
|
||||
#include <unordered_map>
|
||||
|
||||
class CHyprMonitorDebugOverlay {
|
||||
public:
|
||||
int draw(int offset);
|
||||
|
||||
void renderData(SMonitor* pMonitor, float µs);
|
||||
void frameData(SMonitor* pMonitor);
|
||||
|
||||
private:
|
||||
std::deque<float> m_dLastFrametimes;
|
||||
std::deque<float> m_dLastRenderTimes;
|
||||
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
||||
SMonitor* m_pMonitor = nullptr;
|
||||
wlr_box m_wbLastDrawnBox;
|
||||
};
|
||||
|
||||
class CHyprDebugOverlay {
|
||||
public:
|
||||
|
||||
void draw();
|
||||
void renderData(SMonitor*, float µs);
|
||||
void frameData(SMonitor*);
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_map<SMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
|
||||
|
||||
cairo_surface_t* m_pCairoSurface = nullptr;
|
||||
cairo_t* m_pCairo = nullptr;
|
||||
|
||||
CTexture m_tTexture;
|
||||
|
||||
friend class CHyprMonitorDebugOverlay;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
|
@ -131,6 +131,13 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
|||
void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
SMonitor* const PMONITOR = (SMonitor*)owner;
|
||||
|
||||
static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (g_pConfigManager->getInt("debug:overlay") == 1) {
|
||||
startRender = std::chrono::high_resolution_clock::now();
|
||||
g_pDebugOverlay->frameData(PMONITOR);
|
||||
}
|
||||
|
||||
// Hack: only check when monitor with top hz refreshes, saves a bit of resources.
|
||||
// This is for stuff that should be run every frame
|
||||
if (PMONITOR->ID == pMostHzMonitor->ID) {
|
||||
|
@ -213,6 +220,14 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
|||
|
||||
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
|
||||
|
||||
// if correct monitor draw hyprerror
|
||||
if (PMONITOR->ID == 0)
|
||||
g_pHyprError->draw();
|
||||
|
||||
// for drawing the debug overlay
|
||||
if (PMONITOR->ID == 0 && g_pConfigManager->getInt("debug:overlay") == 1)
|
||||
g_pDebugOverlay->draw();
|
||||
|
||||
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
|
||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
||||
|
@ -238,6 +253,9 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
|||
wlr_output_commit(PMONITOR->output);
|
||||
|
||||
wlr_output_schedule_frame(PMONITOR->output);
|
||||
|
||||
if (g_pConfigManager->getInt("debug:overlay") == 1)
|
||||
g_pDebugOverlay->renderData(PMONITOR, std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f);
|
||||
}
|
||||
|
||||
void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
|
|
|
@ -194,10 +194,6 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
|||
}
|
||||
|
||||
renderDragIcon(PMONITOR, time);
|
||||
|
||||
// if correct monitor draw hyprerror
|
||||
if (PMONITOR == &g_pCompositor->m_lMonitors.front())
|
||||
g_pHyprError->draw();
|
||||
}
|
||||
|
||||
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
|
||||
|
|
Loading…
Reference in a new issue