feat: switch to hooking renderWindow and inserting a pass beforehand

This commit is contained in:
Matias 2025-07-12 22:45:19 +02:00
parent 734911c395
commit 81723f4cca
No known key found for this signature in database
GPG Key ID: ED35A6AC65A06B69

View File

@ -3,13 +3,17 @@
#include <hyprgraphics/color/Color.hpp> #include <hyprgraphics/color/Color.hpp>
// version.hpp will be generated by meson // version.hpp will be generated by meson
#include "src/plugins/PluginAPI.hpp"
#include "src/render/Framebuffer.hpp"
#include "src/render/Shader.hpp" #include "src/render/Shader.hpp"
#include "src/render/pass/PassElement.hpp"
#include "src/render/pass/RectPassElement.hpp"
#include "version.hpp" #include "version.hpp"
#include <hyprland/src/Compositor.hpp> #include <hyprland/src/Compositor.hpp>
#include <hyprland/src/desktop/Window.hpp> #include <hyprland/src/desktop/Window.hpp>
#include <hyprland/src/render/Renderer.hpp> #include <hyprland/src/render/Renderer.hpp>
#include <hyprland/src/render/Transformer.hpp> #include <hyprutils/math/Region.hpp>
#include <unistd.h> #include <unistd.h>
// Do NOT change this function. // Do NOT change this function.
@ -17,140 +21,82 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_API_VERSION; return HYPRLAND_API_VERSION;
} }
class CWindowTransformer: public IWindowTransformer { class CBindOwnFramebuffer final: public IPassElement {
public: public:
virtual CFramebuffer* transform(CFramebuffer* in); explicit CBindOwnFramebuffer(CFramebuffer m_framebuffer) :
virtual void preWindowRender(CSurfacePassElement::SRenderData* pRenderData); m_framebuffer(std::move(m_framebuffer)) {}
void draw(const CRegion& damage);
bool needsLiveBlur() {
return true;
}
bool needsPrecomputeBlur() {
return false;
}
const char* passName() {
return "BIND_OWN_FRAMEBUFFER";
}
private: private:
float m_rot = 0; CFramebuffer m_framebuffer;
Vector2D m_prevPos;
}; };
std::vector<CWindowTransformer*> ptrs;
void renderTex(CBox monbox, CTexture& tex, float rot) {
if (g_pHyprOpenGL->m_renderData.damage.empty())
return;
CBox newBox = monbox.scale(g_pHyprOpenGL->m_renderData.renderModif.combinedScale());
g_pHyprOpenGL->m_renderData.renderModif.applyToBox(newBox);
Mat3x3 matrix = g_pHyprOpenGL->m_renderData.monitorProjection.projectBox(
monbox,
wlTransformToHyprutils(invertTransform(WL_OUTPUT_TRANSFORM_NORMAL)),
rot
);
Mat3x3 glMatrix = g_pHyprOpenGL->m_renderData.projection.copy().multiply(matrix);
SShader* shader = &g_pHyprOpenGL->m_shaders->m_shPASSTHRURGBA;
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_target, tex.m_texID);
glUseProgram(shader->program);
glUniformMatrix3fv(
shader->uniformLocations[SHADER_PROJ],
1,
GL_TRUE,
glMatrix.getMatrix().data()
);
glUniform1i(shader->uniformLocations[SHADER_TEX], 0);
const auto TOPLEFT = Vector2D(newBox.x, newBox.y);
const auto FULLSIZE = Vector2D(newBox.width, newBox.height);
glUniform2f(shader->uniformLocations[SHADER_TOP_LEFT], TOPLEFT.x, TOPLEFT.y);
glUniform2f(shader->uniformLocations[SHADER_FULL_SIZE], FULLSIZE.x, FULLSIZE.y);
glUniform1f(shader->uniformLocations[SHADER_RADIUS], 0);
glUniform1i(shader->uniformLocations[SHADER_DISCARD_OPAQUE], 0);
glUniform1i(shader->uniformLocations[SHADER_DISCARD_ALPHA], 0);
glUniform1f(shader->uniformLocations[SHADER_ALPHA], 1);
glVertexAttribPointer(
shader->uniformLocations[SHADER_POS_ATTRIB],
2,
GL_FLOAT,
GL_FALSE,
0,
fullVerts
);
glVertexAttribPointer(
shader->uniformLocations[SHADER_TEX_ATTRIB],
2,
GL_FLOAT,
GL_FALSE,
0,
fullVerts
);
glEnableVertexAttribArray(shader->uniformLocations[SHADER_POS_ATTRIB]);
glEnableVertexAttribArray(shader->uniformLocations[SHADER_TEX_ATTRIB]);
for (auto& RECT : g_pHyprOpenGL->m_renderData.damage.getRects()) {
g_pHyprOpenGL->scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
g_pHyprOpenGL->scissor(nullptr);
glDisableVertexAttribArray(shader->uniformLocations[SHADER_POS_ATTRIB]);
glDisableVertexAttribArray(shader->uniformLocations[SHADER_TEX_ATTRIB]);
glBindTexture(tex.m_target, 0);
}
void CWindowTransformer::preWindowRender(CSurfacePassElement::SRenderData* pRenderData) {
auto&& newPos = pRenderData->pos;
auto delta = newPos - m_prevPos;
m_rot = delta.x * 0.01f;
std::println("delta.x: {}", delta.x);
// pRenderData->pos.x += 50;
pRenderData->rounding = 5;
pRenderData->alpha = 0.9;
m_prevPos = newPos;
}
CFramebuffer* CWindowTransformer::transform(CFramebuffer* in) {
static CFramebuffer off;
if (!off.isAllocated() || off.m_size != in->m_size) {
off.release();
off.alloc(in->m_size.x, in->m_size.y);
}
off.bind();
g_pHyprOpenGL->clear(CHyprColor {0, 0, 0, 0});
CBox monbox = {// m_prevPos.x,
// m_prevPos.y,
0,
0,
g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.x,
g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.y
};
renderTex(monbox, *in->getTexture(), m_rot);
return &off;
}
void onNewWindow(std::any data) { void onNewWindow(std::any data) {
// data is guaranteed // data is guaranteed
auto PWINDOW = std::any_cast<PHLWINDOW>(data); auto PWINDOW = std::any_cast<PHLWINDOW>(data);
ptrs.push_back(static_cast<CWindowTransformer*>(
PWINDOW->m_transformers.emplace_back(new CWindowTransformer {}).get()
));
} }
static SP<HOOK_CALLBACK_FN> g_p = nullptr; static SP<HOOK_CALLBACK_FN> g_openWindow = nullptr;
inline CFunctionHook* g_pRenderWindowHook = nullptr;
typedef void (*origRenderWindow)(
void*,
PHLWINDOW,
PHLMONITOR,
const Time::steady_tp&,
bool,
eRenderPassMode,
bool,
bool
);
void hkRenderWindow(
void* thisptr,
PHLWINDOW pWindow,
PHLMONITOR pMonitor,
const Time::steady_tp& time,
bool decorate,
eRenderPassMode mode,
bool ignorePosition = false,
bool standalone = false
) {
std::println("renderWindow hooked!");
CHyprRenderer* pRenderer = (CHyprRenderer*)thisptr;
CBox monbox =
{pWindow->m_position.x, pWindow->m_position.y, pWindow->m_size.x, pWindow->m_size.y};
// test that it works
CRectPassElement::SRectData data;
data.color = CHyprColor(1, 0, 0, 0.2f);
data.box = monbox;
pRenderer->m_renderPass.add(makeUnique<CRectPassElement>(data));
// then call the original...
(*(origRenderWindow)g_pRenderWindowHook->m_original)(
thisptr,
pWindow,
pMonitor,
time,
decorate,
mode,
ignorePosition,
standalone
);
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle; PHANDLE = handle;
@ -169,12 +115,17 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
throw std::runtime_error("[WiggleWobble] Version mismatch"); throw std::runtime_error("[WiggleWobble] Version mismatch");
} }
g_p = HyprlandAPI::registerCallbackDynamic( g_openWindow = HyprlandAPI::registerCallbackDynamic(
PHANDLE, PHANDLE,
"openWindow", "openWindow",
[](void* self, SCallbackInfo& info, std::any data) { onNewWindow(data); } [](void* self, SCallbackInfo& info, std::any data) { onNewWindow(data); }
); );
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "renderWindow");
g_pRenderWindowHook =
HyprlandAPI::createFunctionHook(handle, METHODS[0].address, (void*)&hkRenderWindow);
g_pRenderWindowHook->hook();
HyprlandAPI::reloadConfig(); HyprlandAPI::reloadConfig();
HyprlandAPI::addNotification( HyprlandAPI::addNotification(
@ -188,5 +139,6 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
} }
APICALL EXPORT void PLUGIN_EXIT() { APICALL EXPORT void PLUGIN_EXIT() {
g_p = nullptr; g_pRenderWindowHook = nullptr;
g_openWindow = nullptr;
} }