added basic damage tracking

This commit is contained in:
vaxerski 2022-04-14 16:43:29 +02:00
parent 158af1eb09
commit 75af34da96
11 changed files with 259 additions and 84 deletions

View file

@ -118,7 +118,7 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
return shader;
}
void CHyprOpenGLImpl::begin(SMonitor* pMonitor) {
void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage) {
m_RenderData.pMonitor = pMonitor;
glViewport(0, 0, pMonitor->vecSize.x, pMonitor->vecSize.y);
@ -145,20 +145,21 @@ void CHyprOpenGLImpl::begin(SMonitor* pMonitor) {
// bind the primary Hypr Framebuffer
m_mMonitorRenderResources[pMonitor].primaryFB.bind();
m_RenderData.pDamage = pDamage;
// clear
clear(CColor(11, 11, 11, 255));
}
void CHyprOpenGLImpl::end() {
// end the render, copy the data to the WLR framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb);
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
float matrix[9];
wlr_box windowBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
clear(CColor(11, 11, 11, 255));
renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, matrix, 255.f, 0);
renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, &windowBox, 255.f, 0);
// reset our data
m_RenderData.pMonitor = nullptr;
@ -169,7 +170,15 @@ void CHyprOpenGLImpl::clear(const CColor& color) {
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glClear(GL_COLOR_BUFFER_BIT);
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glClear(GL_COLOR_BUFFER_BIT);
}
}
}
void CHyprOpenGLImpl::scissor(const wlr_box* pBox) {
@ -184,10 +193,24 @@ void CHyprOpenGLImpl::scissor(const wlr_box* pBox) {
glEnable(GL_SCISSOR_TEST);
}
void CHyprOpenGLImpl::scissor(const pixman_box32* pBox) {
RASSERT(m_RenderData.pMonitor, "Tried to scissor without begin()!");
if (!pBox) {
glDisable(GL_SCISSOR_TEST);
return;
}
glScissor(pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1);
glEnable(GL_SCISSOR_TEST);
}
void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col) {
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
// TODO: respect damage
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here
@ -216,16 +239,34 @@ void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col) {
glDisableVertexAttribArray(m_shQUAD.posAttrib);
}
void CHyprOpenGLImpl::renderTexture(wlr_texture* tex,float matrix[9], float alpha, int round) {
void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha, int round) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTexture(CTexture(tex), matrix, alpha, round);
renderTexture(CTexture(tex), pBox, alpha, round);
}
void CHyprOpenGLImpl::renderTexture(const CTexture& tex, float matrix[9], float alpha, int round) {
void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
renderTextureInternal(tex, pBox, alpha, round);
}
}
}
void CHyprOpenGLImpl::renderTextureInternal(const CTexture& tex, wlr_box* pBox, float alpha, int round) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
// get transform
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
float matrix[9];
wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
@ -293,16 +334,21 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, float matrix[9], float
// cheers.
// 2-pass pseudo-gaussian blur
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9], float a, int round) {
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, int round) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
// if blur disabled, just render the texture
if (g_pConfigManager->getInt("decoration:blur") == 0) {
renderTexture(tex, matrix, a, round);
renderTexture(tex, pBox, a, round);
return;
}
// get transform
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
float matrix[9];
wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
// bind the mirror FB and clear it.
m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.bind();
clear(CColor(0, 0, 0, 0));
@ -317,7 +363,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9]
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
// render our window to the mirror FB while also writing to the stencil
renderTexture(tex, matrix, a, round);
renderTexture(tex, pBox, a, round);
// then we disable writing to the mask and ONLY accept writing within the stencil
glStencilFunc(GL_EQUAL, 1, -1);
@ -332,7 +378,6 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9]
// now we make the blur by blurring the main framebuffer (it will only affect the stencil)
// matrix
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
float matrixFull[9];
wlr_box fullMonBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
wlr_matrix_project_box(matrixFull, &fullMonBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
@ -382,7 +427,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9]
// when the blur is done, let's render the window itself
// we get it from the mirrored FB full because it's the FB 255 alpha cuz we rendered with a before, same for rounding
renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex, matrixFull, 255.f, 0);
renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex, &fullMonBox, 255.f, 0);
// and disable the stencil
glStencilMask(-1);
@ -485,7 +530,16 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
wlr_output_attach_render(PMONITOR->output, nullptr);
begin(PMONITOR);
// we need to "damage" the entire monitor
// so that we render the entire window
// this is temporary, doesnt mess with the actual wlr damage
pixman_region32_t fakeDamage;
pixman_region32_init(&fakeDamage);
pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y);
begin(PMONITOR, &fakeDamage);
pixman_region32_fini(&fakeDamage);
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
@ -541,12 +595,9 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto TRANSFORM = wlr_output_transform_invert(it->second.m_tTransform);
float matrix[9];
wlr_box windowBox = {0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, PMONITOR->output->transform_matrix);
renderTexture(it->second.m_cTex, matrix, PWINDOW->m_fAlpha, 0);
renderTexture(it->second.m_cTex, &windowBox, PWINDOW->m_fAlpha, 0);
}
void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) {
@ -603,10 +654,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) {
void CHyprOpenGLImpl::clearWithTex() {
RASSERT(m_RenderData.pMonitor, "Tried to render BGtex without begin()!");
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
float matrix[9];
wlr_box box = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
wlr_matrix_project_box(matrix, &box, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], matrix, 255, 0);
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0);
}

View file

@ -27,6 +27,8 @@ inline const float fullVerts[] = {
struct SCurrentRenderData {
SMonitor* pMonitor = nullptr;
float projection[9];
pixman_region32_t* pDamage = nullptr;
};
struct SMonitorRenderData {
@ -41,13 +43,13 @@ public:
CHyprOpenGLImpl();
void begin(SMonitor*);
void begin(SMonitor*, pixman_region32_t*);
void end();
void renderRect(wlr_box*, const CColor&);
void renderTexture(wlr_texture*, float matrix[9], float a, int round = 0);
void renderTexture(const CTexture&, float matrix[9], float a, int round = 0);
void renderTextureWithBlur(const CTexture&, float matrix[9], float a, int round = 0);
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0);
void renderTexture(const CTexture&, wlr_box*, float a, int round = 0);
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, int round = 0);
void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0);
void makeWindowSnapshot(CWindow*);
@ -56,6 +58,7 @@ public:
void clear(const CColor&);
void clearWithTex();
void scissor(const wlr_box*);
void scissor(const pixman_box32*);
SCurrentRenderData m_RenderData;
@ -85,6 +88,9 @@ private:
GLuint createProgram(const std::string&, const std::string&);
GLuint compileShader(const GLuint&, std::string);
void createBGTextureForMonitor(SMonitor*);
void renderTextureInternal(const CTexture&, wlr_box* pBox, float a, int round = 0);
};
inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;

View file

@ -27,20 +27,14 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
}
scaleBox(&windowBox, RDATA->output->scale);
const auto TRANSFORM = wlr_output_transform_invert(surface->current.transform);
float matrix[9];
wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, RDATA->output->transform_matrix);
if (RDATA->surface && surface == RDATA->surface)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
else
g_pHyprOpenGL->renderTexture(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
wlr_surface_send_frame_done(surface, RDATA->when);
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
g_pHyprOpenGL->scissor(nullptr);
}
bool shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) {
@ -432,51 +426,52 @@ void CHyprRenderer::drawBorderForWindow(CWindow* pWindow, SMonitor* pMonitor, fl
g_pHyprOpenGL->renderBorder(&border, BORDERCOL, BORDERSIZE, g_pConfigManager->getInt("decoration:rounding"));
}
void damageSurfaceIter(struct wlr_surface* surface, int x, int y, void* data) {
auto* renderdata = (SRenderData*)data;
bool entire = (bool*)renderdata->data;
void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
if (!pSurface)
return; // wut?
wlr_box box = {.x = renderdata->x, .y = renderdata->y, .width = renderdata->w, .height = renderdata->h};
scaleBox(&box, renderdata->output->scale);
pixman_region32_t damageBox;
pixman_region32_init(&damageBox);
wlr_surface_get_effective_damage(pSurface, &damageBox);
pixman_region32_t damageRegion;
pixman_region32_init(&damageRegion);
wlr_surface_get_effective_damage(renderdata->surface, &damageRegion);
wlr_region_scale(&damageRegion, &damageRegion, renderdata->output->scale);
pixman_region32_translate(&damageBox, x, y);
if (std::ceil(renderdata->output->scale) > renderdata->surface->current.scale) {
wlr_region_expand(&damageRegion, &damageRegion, std::ceil(renderdata->output->scale) - renderdata->surface->current.scale);
for (auto& m : g_pCompositor->m_lMonitors) {
double lx = 0, ly = 0;
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m.output, &lx, &ly);
pixman_region32_translate(&damageBox, lx, ly);
wlr_output_damage_add(m.damage, &damageBox);
pixman_region32_translate(&damageBox, -lx, -ly);
}
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(renderdata->output);
pixman_region32_fini(&damageBox);
}
pixman_region32_translate(&damageRegion, box.x, box.y);
wlr_output_damage_add(PMONITOR->damage, &damageRegion);
pixman_region32_fini(&damageRegion);
void CHyprRenderer::damageWindow(CWindow* pWindow) {
if (!pWindow->m_bIsFloating) {
// damage by size & pos
// TODO TEMP: revise when added shadows/etc
if (entire)
wlr_output_damage_add_box(PMONITOR->damage, &box);
if (!wl_list_empty(&surface->current.frame_callback_list)) {
wlr_output_schedule_frame(renderdata->output);
wlr_box damageBox = {pWindow->m_vPosition.x, pWindow->m_vPosition.y, pWindow->m_vSize.x, pWindow->m_vSize.y};
for (auto& m : g_pCompositor->m_lMonitors)
wlr_output_damage_add_box(m.damage, &damageBox);
} else {
// damage by effective size & pos + border size + 1 (JIC)
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
wlr_box damageBox = { pWindow->m_vEffectivePosition.x - BORDERSIZE - 1, pWindow->m_vEffectivePosition.y - BORDERSIZE - 1, pWindow->m_vEffectiveSize.x + 2 * BORDERSIZE + 2, pWindow->m_vEffectiveSize.y + 2 * BORDERSIZE + 2};
for (auto& m : g_pCompositor->m_lMonitors)
wlr_output_damage_add_box(m.damage, &damageBox);
}
}
void CHyprRenderer::damageSurface(SMonitor* pMonitor, double x, double y, wlr_surface* pSurface, void* data) {
if (!pSurface || !pMonitor)
return; // wut?
void CHyprRenderer::damageMonitor(SMonitor* pMonitor) {
wlr_box damageBox = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y};
wlr_output_damage_add_box(pMonitor->damage, &damageBox);
}
SRenderData renderData = {
.output = pMonitor->output,
.x = x,
.y = y,
.data = data,
.surface = pSurface,
.w = pSurface->current.width,
.h = pSurface->current.height
};
wlr_surface_for_each_surface(pSurface, damageSurfaceIter, &renderData);
void CHyprRenderer::damageBox(wlr_box* pBox) {
for (auto& m : g_pCompositor->m_lMonitors)
wlr_output_damage_add_box(m.damage, pBox);
}
void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) {
@ -489,4 +484,15 @@ void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) {
renderdata.h = g_pInputManager->m_sDrag.dragIcon->surface->current.height;
wlr_surface_for_each_surface(g_pInputManager->m_sDrag.dragIcon->surface, renderSurface, &renderdata);
}
DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& mode) {
if (mode == "full")
return DAMAGE_TRACKING_FULL;
if (mode == "monitor")
return DAMAGE_TRACKING_MONITOR;
if (mode == "none")
return DAMAGE_TRACKING_NONE;
return DAMAGE_TRACKING_INVALID;
}

View file

@ -7,13 +7,26 @@
#include "../Window.hpp"
#include "OpenGL.hpp"
// TODO: add fuller damage tracking for updating only parts of a window
enum DAMAGETRACKINGMODES {
DAMAGE_TRACKING_INVALID = -1,
DAMAGE_TRACKING_NONE = 0,
DAMAGE_TRACKING_MONITOR,
DAMAGE_TRACKING_FULL
};
class CHyprRenderer {
public:
void renderAllClientsForMonitor(const int&, timespec*);
void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
void arrangeLayersForMonitor(const int&);
void damageSurface(SMonitor*, double, double, wlr_surface*, void*);
void damageSurface(wlr_surface*, double, double);
void damageWindow(CWindow*);
void damageBox(wlr_box*);
void damageMonitor(SMonitor*);
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
private:
void arrangeLayerArray(SMonitor*, const std::list<SLayerSurface*>&, bool, wlr_box*);