feat: basic inverted rendering

This commit is contained in:
Virt 2024-06-30 11:10:42 +02:00
commit 69e2583e57
7 changed files with 333 additions and 1 deletions

View file

@ -10,6 +10,11 @@
#define CONFIG_THRESHOLD "threshold" #define CONFIG_THRESHOLD "threshold"
#define CONFIG_HW_DEBUG "hw_debug" #define CONFIG_HW_DEBUG "hw_debug"
#define CONFIG_INVERT "plugin:dynamic-cursors:invert"
#define CONFIG_INVERT_SHADER "plugin:dynamic-cursors:invert:shader"
#define CONFIG_INVERT_CHROMA "plugin:dynamic-cursors:invert:chroma"
#define CONFIG_INVERT_CHROMA_COLOR "plugin:dynamic-cursors:invert:chroma:color"
#define CONFIG_SHAKE "shake:enabled" #define CONFIG_SHAKE "shake:enabled"
#define CONFIG_SHAKE_NEAREST "shake:nearest" #define CONFIG_SHAKE_NEAREST "shake:nearest"
#define CONFIG_SHAKE_THRESHOLD "shake:threshold" #define CONFIG_SHAKE_THRESHOLD "shake:threshold"

View file

@ -54,7 +54,12 @@ Reimplements rendering of the software cursor.
Is also largely identical to hyprlands impl, but uses our custom rendering to rotate the cursor. Is also largely identical to hyprlands impl, but uses our custom rendering to rotate the cursor.
*/ */
void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) { void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
<<<<<<< HEAD
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST); static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
=======
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
>>>>>>> c8ae8fe (feat: basic inverted rendering)
if (!pointers->hasCursor()) if (!pointers->hasCursor())
return; return;
@ -94,10 +99,17 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
box.rot = resultShown.rotation; box.rot = resultShown.rotation;
// now pass the hotspot to rotate around // now pass the hotspot to rotate around
<<<<<<< HEAD
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, nullptr, 0, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST, resultShown.stretch.angle, resultShown.stretch.magnitude); renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, nullptr, 0, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST, resultShown.stretch.angle, resultShown.stretch.magnitude);
if (pointers->currentCursorImage.surface) if (pointers->currentCursorImage.surface)
pointers->currentCursorImage.surface->resource()->frame(now); pointers->currentCursorImage.surface->resource()->frame(now);
=======
if (**PINVERT)
renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
else
renderCursorTextureInternalWithDamage(texture, &box, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
>>>>>>> c8ae8fe (feat: basic inverted rendering)
} }
/* /*
@ -131,9 +143,16 @@ void CDynamicCursors::damageSoftware(CPointerManager* pointers) {
This function reimplements the hardware cursor buffer drawing. This function reimplements the hardware cursor buffer drawing.
It is largely copied from hyprland, but adjusted to allow the cursor to be rotated. It is largely copied from hyprland, but adjusted to allow the cursor to be rotated.
*/ */
<<<<<<< HEAD
SP<Aquamarine::IBuffer> CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) { SP<Aquamarine::IBuffer> CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
static auto* const* PHW_DEBUG = (Hyprlang::INT* const*) getConfig(CONFIG_HW_DEBUG); static auto* const* PHW_DEBUG = (Hyprlang::INT* const*) getConfig(CONFIG_HW_DEBUG);
static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST); static auto* const* PNEAREST = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE_NEAREST);
=======
wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
static auto* const* PHW_DEBUG= (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_HW_DEBUG)->getDataStaticPtr();
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
>>>>>>> c8ae8fe (feat: basic inverted rendering)
auto output = state->monitor->output; auto output = state->monitor->output;
@ -243,7 +262,14 @@ SP<Aquamarine::IBuffer> CDynamicCursors::renderHardware(CPointerManager* pointer
xbox.rot = resultShown.rotation; xbox.rot = resultShown.rotation;
// use our custom draw function // use our custom draw function
<<<<<<< HEAD
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.waitTimeline, pointers->currentCursorImage.waitPoint, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST, resultShown.stretch.angle, resultShown.stretch.magnitude); renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.waitTimeline, pointers->currentCursorImage.waitPoint, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST, resultShown.stretch.angle, resultShown.stretch.magnitude);
=======
if (**PINVERT)
renderCursorTextureInternalWithDamageInverted(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
else
renderCursorTextureInternalWithDamage(texture, &xbox, &damage, 1.F, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom > 1 && **PNEAREST);
>>>>>>> c8ae8fe (feat: basic inverted rendering)
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
glFlush(); glFlush();

42
src/invert/shader.cpp Normal file
View file

@ -0,0 +1,42 @@
#include "src/debug/Log.hpp"
#define private public
#include <hyprland/src/render/OpenGL.hpp>
#undef private
#include <hyprland/src/Compositor.hpp>
#include <hyprland/src/render/Shaders.hpp>
#include "shader.hpp"
void CInversionShader::compile(std::string vertex, std::string fragment) {
program = g_pHyprOpenGL->createProgram(vertex, fragment);
texAttrib = glGetAttribLocation(program, "texcoord");
posAttrib = glGetAttribLocation(program, "pos");
proj = glGetUniformLocation(program, "proj");
backgroundTex = glGetUniformLocation(program, "backgroundTex");
cursorTex = glGetUniformLocation(program, "cursorTex");
alpha = glGetUniformLocation(program, "alpha");
applyTint = glGetUniformLocation(program, "applyTint");
tint = glGetUniformLocation(program, "tint");
}
CInversionShader::~CInversionShader() {
glDeleteProgram(program);
program = 0;
}
CShaders::CShaders() {
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
"Couldn't set current EGL!");
rgba.compile(VERTEX, RGBA);
ext.compile(VERTEX, EXT);
rgbx.compile(VERTEX, RGBX);
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
"Couldn't set current EGL!");
}

152
src/invert/shader.hpp Normal file
View file

@ -0,0 +1,152 @@
#include <string>
#include <hyprland/src/render/Shader.hpp>
// we need our own shader class as we have two textures
class CInversionShader {
public:
GLuint program = 0;
GLint proj = -1;
GLint color = -1;
GLint alphaMatte = -1;
GLint cursorTex = -1;
GLint backgroundTex = -1;
GLint alpha = -1;
GLint posAttrib = -1;
GLint texAttrib = -1;
GLint matteTexAttrib = -1;
GLint discardOpaque = -1;
GLint discardAlpha = -1;
GLfloat discardAlphaValue = -1;
GLint applyTint = -1;
GLint tint = -1;
void compile(std::string vertex, std::string fragment);
~CInversionShader();
};
class CShaders {
public:
CInversionShader rgba;
CInversionShader rgbx;
CInversionShader ext;
CShaders();
};
inline std::unique_ptr<CShaders> g_pShaders;
inline const std::string VERTEX = R"#(
uniform mat3 proj;
attribute vec2 pos;
attribute vec2 texcoord;
varying vec2 v_texcoord;
varying vec2 v_screencord;
void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
v_screencord = gl_Position.xy / 2.0 + vec2(0.5, 0.5); // transform to texture coords
v_texcoord = texcoord;
}
)#";
inline const std::string RGBA = R"#(
precision highp float;
varying vec2 v_texcoord; // is in 0-1
varying vec2 v_screencord; // is in 0-1
uniform sampler2D cursorTex;
uniform sampler2D backgroundTex;
uniform float alpha;
uniform int applyTint;
uniform vec3 tint;
void main() {
vec4 cursor = texture2D(cursorTex, v_texcoord);
// load and invert background
vec4 background = texture2D(backgroundTex, v_screencord);
background.rgb = vec3(1.0, 1.0, 1.0) - background.rgb;
background *= cursor[3]; // premultiplied alpha
// invert hue
//background.rgb = -background.rgb + dot(vec3(0.26312, 0.5283, 0.10488), background.rgb) * 2.0;
vec4 pixColor = cursor;
//if (cursor[3] != 1.0) pixColor = cursor;
//pixColor = vec4(v_screencord + vec2(1.0, 1.0) / 2.0, 0.0, 1.0);
vec4 chroma = vec4(0.0, 0.0, 0.0, 1.0);
float diff = (abs(chroma.x - cursor.x) + abs(chroma.y - cursor.y) + abs(chroma.z - cursor.z) + abs(chroma.w - cursor.w)) / 4.0;
pixColor = background * (1.0 - diff) + cursor * diff;
if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
gl_FragColor = pixColor * alpha;
}
)#";
inline const std::string RGBX = R"#(
precision highp float;
varying vec2 v_texcoord;
uniform sampler2D cursorTex;
uniform sampler2D backgroundTex;
uniform float alpha;
uniform int applyTint;
uniform vec3 tint;
void main() {
vec4 pixColor = vec4(texture2D(cursorTex, v_texcoord).rgb, 1.0);
if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
pixColor.r = 1.0;
gl_FragColor = pixColor * alpha;
}
)#";
inline const std::string EXT = R"#(
#extension GL_OES_EGL_image_external : require
precision highp float;
varying vec2 v_texcoord;
uniform samplerExternalOES texture0;
uniform samplerExternalOES texture1;
uniform float alpha;
uniform int applyTint;
uniform vec3 tint;
void main() {
vec4 pixColor = texture2D(texture0, v_texcoord);
if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
pixColor.r = 1.0;
gl_FragColor = pixColor * alpha;
}
)#";

View file

@ -10,6 +10,7 @@
#include "cursor.hpp" #include "cursor.hpp"
#include "config/config.hpp" #include "config/config.hpp"
#include "src/debug/Log.hpp" #include "src/debug/Log.hpp"
#include "invert/shader.hpp"
#include "src/managers/PointerManager.hpp" #include "src/managers/PointerManager.hpp"
#include "src/version.h" #include "src/version.h"
@ -112,6 +113,11 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
addConfig(CONFIG_SHAKE_THRESHOLD, 4.0f); addConfig(CONFIG_SHAKE_THRESHOLD, 4.0f);
addConfig(CONFIG_SHAKE_FACTOR, 1.5f); addConfig(CONFIG_SHAKE_FACTOR, 1.5f);
addConfig(CONFIG_INVERT, 0);
addConfig(CONFIG_INVERT_SHADER, "normal");
addConfig(CONFIG_INVERT_CHROMA, 0);
addConfig(CONFIG_INVERT_CHROMA_COLOR, 0xFF000000); // opaque black
addShapeConfig(CONFIG_TILT_FUNCTION, "negative_quadratic"); addShapeConfig(CONFIG_TILT_FUNCTION, "negative_quadratic");
addShapeConfig(CONFIG_TILT_LIMIT, 5000); addShapeConfig(CONFIG_TILT_LIMIT, 5000);
@ -128,6 +134,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
// init things // init things
g_pDynamicCursors = std::make_unique<CDynamicCursors>(); g_pDynamicCursors = std::make_unique<CDynamicCursors>();
g_pShaders = std::make_unique<CShaders>();
// try hooking // try hooking
try { try {

View file

@ -11,6 +11,7 @@
#include <hyprland/src/config/ConfigValue.hpp> #include <hyprland/src/config/ConfigValue.hpp>
#include "renderer.hpp" #include "renderer.hpp"
#include "invert/shader.hpp"
/* /*
This is the projectBox method from hyprland, but with support for rotation around a point, the hotspot. This is the projectBox method from hyprland, but with support for rotation around a point, the hotspot.
@ -156,3 +157,101 @@ void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion
glBindTexture(tex->m_iTarget, 0); glBindTexture(tex->m_iTarget, 0);
} }
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, SP<CSyncTimeline> waitTimeline, uint64_t waitPoint, Vector2D hotspot, bool nearest, float stretchAngle, Vector2D stretch, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset) {
TRACY_GPU_ZONE("RenderDynamicCursor");
if (waitTimeline != nullptr) {
if (!g_pHyprOpenGL->waitForTimelinePoint(waitTimeline, waitPoint)) {
Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint);
return;
}
}
alpha = std::clamp(alpha, 0.f, 1.f);
if (damage->empty())
return;
CBox newBox = *pBox;
g_pHyprOpenGL->m_RenderData.renderModif.applyToBox(newBox);
// get transform
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!g_pHyprOpenGL->m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : g_pHyprOpenGL->m_RenderData.pMonitor->transform));
float matrix[9];
projectCursorBox(matrix, newBox, TRANSFORM, newBox.rot, g_pHyprOpenGL->m_RenderData.monitorProjection.data(), hotspot, stretchAngle, stretch);
float glMatrix[9];
matrixMultiply(glMatrix, g_pHyprOpenGL->m_RenderData.projection, matrix);
CInversionShader* shader = nullptr;
switch (tex->m_iType) {
case TEXTURE_RGBA: shader = &g_pShaders->rgba; break;
case TEXTURE_RGBX: shader = &g_pShaders->rgbx; break;
case TEXTURE_EXTERNAL: shader = &g_pShaders->ext; break;
default: RASSERT(false, "tex->m_iTarget unsupported!");
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
if (g_pHyprOpenGL->m_RenderData.useNearestNeighbor || nearest) {
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glUseProgram(shader->program);
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform2f(shader->screenOffset, screenOffset.x, screenOffset.y);
glUniform1i(shader->backgroundTex, 0);
glUniform1i(shader->cursorTex, 1);
glUniform1f(shader->alpha, alpha);
glUniform1i(shader->mode, mode);
glUniform1i(shader->chroma, chroma);
glUniform4f(shader->chromaColor, chromaColor.r, chromaColor.g, chromaColor.b, chromaColor.a);
CBox transformedBox = newBox;
transformedBox.transform(wlTransformToHyprutils(invertTransform(g_pHyprOpenGL->m_RenderData.pMonitor->transform)), g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y);
glUniform1i(shader->applyTint, 0);
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib);
if (g_pHyprOpenGL->m_RenderData.clipBox.width != 0 && g_pHyprOpenGL->m_RenderData.clipBox.height != 0) {
CRegion damageClip{g_pHyprOpenGL->m_RenderData.clipBox.x, g_pHyprOpenGL->m_RenderData.clipBox.y, g_pHyprOpenGL->m_RenderData.clipBox.width, g_pHyprOpenGL->m_RenderData.clipBox.height};
damageClip.intersect(*damage);
if (!damageClip.empty()) {
for (auto& RECT : damageClip.getRects()) {
g_pHyprOpenGL->scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
} else {
for (auto& RECT : damage->getRects()) {
g_pHyprOpenGL->scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
glDisableVertexAttribArray(shader->posAttrib);
glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex->m_iTarget, 0);
}

View file

@ -2,3 +2,4 @@
#include <hyprland/src/helpers/math/Math.hpp> #include <hyprland/src/helpers/math/Math.hpp>
void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, SP<CSyncTimeline> waitTimeline, uint64_t waitPoint, Vector2D hotspot, bool nearest, float stretchAngle, Vector2D stretch); void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, SP<CSyncTimeline> waitTimeline, uint64_t waitPoint, Vector2D hotspot, bool nearest, float stretchAngle, Vector2D stretch);
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, SP<CSyncTimeline> waitTimeline, uint64_t waitPoint, Vector2D hotspot, bool nearest, float stretchAngle, Vector2D stretch, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset);