mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-01 20:46: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!");
|
Debug::log(LOG, "Creating the EventManager!");
|
||||||
g_pEventManager = std::make_unique<CEventManager>();
|
g_pEventManager = std::make_unique<CEventManager>();
|
||||||
g_pEventManager->startThread();
|
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/KeybindManager.hpp"
|
||||||
#include "managers/AnimationManager.hpp"
|
#include "managers/AnimationManager.hpp"
|
||||||
#include "managers/EventManager.hpp"
|
#include "managers/EventManager.hpp"
|
||||||
|
#include "debug/HyprDebugOverlay.hpp"
|
||||||
#include "helpers/Monitor.hpp"
|
#include "helpers/Monitor.hpp"
|
||||||
#include "helpers/Workspace.hpp"
|
#include "helpers/Workspace.hpp"
|
||||||
#include "Window.hpp"
|
#include "Window.hpp"
|
||||||
|
|
|
@ -35,6 +35,7 @@ void CConfigManager::setDefaultVars() {
|
||||||
|
|
||||||
configValues["debug:int"].intValue = 0;
|
configValues["debug:int"].intValue = 0;
|
||||||
configValues["debug:log_damage"].intValue = 0;
|
configValues["debug:log_damage"].intValue = 0;
|
||||||
|
configValues["debug:overlay"].intValue = 0;
|
||||||
|
|
||||||
configValues["decoration:rounding"].intValue = 1;
|
configValues["decoration:rounding"].intValue = 1;
|
||||||
configValues["decoration:blur"].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) {
|
void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
SMonitor* const PMONITOR = (SMonitor*)owner;
|
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.
|
// Hack: only check when monitor with top hz refreshes, saves a bit of resources.
|
||||||
// This is for stuff that should be run every frame
|
// This is for stuff that should be run every frame
|
||||||
if (PMONITOR->ID == pMostHzMonitor->ID) {
|
if (PMONITOR->ID == pMostHzMonitor->ID) {
|
||||||
|
@ -213,6 +220,14 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
|
|
||||||
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
|
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_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||||
|
|
||||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
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_commit(PMONITOR->output);
|
||||||
|
|
||||||
wlr_output_schedule_frame(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) {
|
void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||||
|
|
|
@ -194,10 +194,6 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDragIcon(PMONITOR, 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) {
|
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
|
||||||
|
|
Loading…
Reference in a new issue