feat: inverted hardware cursor support

This commit is contained in:
Virt 2024-06-30 17:32:53 +02:00
commit 556a124314
7 changed files with 33 additions and 23 deletions

View file

@ -26,9 +26,9 @@ https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/9ff64a9b-64e5-4
### inverted cursor (experimental) ### inverted cursor (experimental)
You can also finally have an inverted cursor with this plugin. This is similar to the inverted cursor theme found in MS Windows. You can also finally have an inverted cursor with this plugin. This is similar to the inverted cursor theme found in MS Windows.
**Note:** Inverted cursors have about the same performance impact as a *basic* screen shader. They are also only supported as software cursors. **Note:** Inverted cursors have about the same performance impact as a *basic* screen shader. They are also currently broken on nvidia.
INSERT VIDEO HERE https://github.com/VirtCode/hypr-dynamic-cursors/assets/41426325/b62698d8-d53f-45f2-b36f-2c9752b8f90d
## state ## state
This plugin is still very early in its development. There are also multiple things which may or may not be implemented in the future: This plugin is still very early in its development. There are also multiple things which may or may not be implemented in the future:

View file

@ -5,6 +5,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <hyprlang.hpp> #include <hyprlang.hpp>
#include <hyprutils/math/Vector2D.hpp>
#define private public #define private public
#include <hyprland/src/managers/PointerManager.hpp> #include <hyprland/src/managers/PointerManager.hpp>
@ -22,7 +23,7 @@
#include "cursor.hpp" #include "cursor.hpp"
#include "renderer.hpp" #include "renderer.hpp"
void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D hotspot, float zoom) { void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D hotspot, float zoom, Vector2D offset) {
static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr(); static auto* const* PNEAREST = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_NEAREST)->getDataStaticPtr();
static auto* const* POPACITY = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_OPACITY)->getDataStaticPtr(); static auto* const* POPACITY = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_OPACITY)->getDataStaticPtr();
@ -39,7 +40,7 @@ void renderCursorBox(SP<CTexture> texture, CBox box, CRegion& damage, Vector2D h
if (!strcmp(*PINVERT_MODE, "invert_hue")) mode = 1; if (!strcmp(*PINVERT_MODE, "invert_hue")) mode = 1;
else if (!strcmp(*PINVERT_MODE, "hue")) mode = 2; else if (!strcmp(*PINVERT_MODE, "hue")) mode = 2;
renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, alpha, hotspot, nearest, mode, **PINVERT_CHROMA, CColor(**PINVERT_CHROMA_COLOR)); renderCursorTextureInternalWithDamageInverted(texture, &box, &damage, alpha, hotspot, nearest, mode, **PINVERT_CHROMA, CColor(**PINVERT_CHROMA_COLOR), offset);
} else } else
renderCursorTextureInternalWithDamage(texture, &box, &damage, alpha, hotspot, nearest); renderCursorTextureInternalWithDamage(texture, &box, &damage, alpha, hotspot, nearest);
} }
@ -83,7 +84,7 @@ void CDynamicCursors::renderSoftware(CPointerManager* pointers, SP<CMonitor> pMo
// we rotate the cursor by our calculated amount // we rotate the cursor by our calculated amount
box.rot = this->angle; box.rot = this->angle;
renderCursorBox(texture, box, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom); renderCursorBox(texture, box, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom, Vector2D());
} }
/* /*
@ -115,6 +116,7 @@ It is largely copied from hyprland, but adjusted to allow the cursor to be rotat
*/ */
wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) { 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* PHW_DEBUG= (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_HW_DEBUG)->getDataStaticPtr();
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
auto output = state->monitor->output; auto output = state->monitor->output;
@ -182,7 +184,19 @@ wlr_buffer* CDynamicCursors::renderHardware(CPointerManager* pointers, SP<CPoint
CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()}; CBox xbox = {size, Vector2D{pointers->currentCursorImage.size / pointers->currentCursorImage.scale * state->monitor->scale * zoom}.round()};
xbox.rot = this->angle; xbox.rot = this->angle;
renderCursorBox(texture, xbox, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom); // calculate correct offset of the offload buffer into the cursor buffer
auto offset = Vector2D();
if (**PINVERT) {
const auto HOTSPOT = CBox{((pointers->currentCursorImage.hotspot * state->monitor->scale) + pointers->currentCursorImage.size) * zoom, {0, 0}}
.transform(wlTransformToHyprutils(wlr_output_transform_invert(state->monitor->transform)), state->monitor->output->cursor_swapchain->width, state->monitor->output->cursor_swapchain->height)
.pos();
offset = pointers->getCursorPosForMonitor(state->monitor.lock()) - HOTSPOT;
offset.x /= xbox.x;
offset.y /= xbox.y;
}
renderCursorBox(texture, xbox, damage, pointers->currentCursorImage.hotspot * state->monitor->scale * zoom, zoom, offset);
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
glFlush(); glFlush();
@ -268,16 +282,6 @@ void CDynamicCursors::beforeRender(CPointerManager* pointers) {
if (**PINVERT) { if (**PINVERT) {
// we need introspection as we make use of the offloadFB // we need introspection as we make use of the offloadFB
g_pHyprOpenGL->m_RenderData.forceIntrospection = true; g_pHyprOpenGL->m_RenderData.forceIntrospection = true;
if (!invertSoftware) {
pointers->lockSoftwareAll();
invertSoftware = true;
}
} else {
if (invertSoftware) {
pointers->unlockSoftwareAll();
invertSoftware = false;
}
} }
} }
@ -285,6 +289,7 @@ void CDynamicCursors::calculate(EModeUpdate type) {
static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr(); static auto* const* PTHRESHOLD = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_THRESHOLD)->getDataStaticPtr();
static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr(); static auto* const* PSHAKE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE)->getDataStaticPtr();
static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr(); static auto* const* PSHAKE_EFFECTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_SHAKE_EFFECTS)->getDataStaticPtr();
static auto* const* PINVERT = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, CONFIG_INVERT)->getDataStaticPtr();
IMode* mode = currentMode(); IMode* mode = currentMode();
@ -304,7 +309,8 @@ void CDynamicCursors::calculate(EModeUpdate type) {
if ( if (
std::abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD) || std::abs(this->angle - angle) > ((PI / 180) * **PTHRESHOLD) ||
this->zoom - zoom != 0 // we don't have a threshold here as this will not happen that often this->zoom - zoom != 0 || // we don't have a threshold here as this will not happen that often
(**PINVERT && type == MOVE) // currently we only update inverted cursors on move
) { ) {
this->zoom = zoom; this->zoom = zoom;
this->angle = angle; this->angle = angle;

View file

@ -35,8 +35,6 @@ class CDynamicCursors {
// whether we have already locked software for cursor zoom // whether we have already locked software for cursor zoom
bool zoomSoftware = false; bool zoomSoftware = false;
// whether we have already locked software for inverted cursors
bool invertSoftware = false;
// modes // modes
CModeRotate rotate; CModeRotate rotate;

View file

@ -17,6 +17,7 @@ void CInversionShader::compile(std::string vertex, std::string fragment) {
posAttrib = glGetAttribLocation(program, "pos"); posAttrib = glGetAttribLocation(program, "pos");
proj = glGetUniformLocation(program, "proj"); proj = glGetUniformLocation(program, "proj");
screenOffset = glGetUniformLocation(program, "screenOffset");
backgroundTex = glGetUniformLocation(program, "backgroundTex"); backgroundTex = glGetUniformLocation(program, "backgroundTex");
cursorTex = glGetUniformLocation(program, "cursorTex"); cursorTex = glGetUniformLocation(program, "cursorTex");
alpha = glGetUniformLocation(program, "alpha"); alpha = glGetUniformLocation(program, "alpha");

View file

@ -1,7 +1,7 @@
#include <string> #include <string>
#include <hyprland/src/render/Shader.hpp> #include <hyprland/src/render/Shader.hpp>
// we need our own shader class as we have two textures // we need our own shader class as we have two textures, and custom uniforms
class CInversionShader { class CInversionShader {
public: public:
GLuint program = 0; GLuint program = 0;
@ -10,6 +10,7 @@ class CInversionShader {
GLint texAttrib = -1; GLint texAttrib = -1;
GLint proj = -1; GLint proj = -1;
GLint screenOffset = -1;
GLint cursorTex = -1; GLint cursorTex = -1;
GLint backgroundTex = -1; GLint backgroundTex = -1;
GLint alpha = -1; GLint alpha = -1;
@ -44,10 +45,12 @@ inline const std::string VERTEX = R"#(
varying vec2 v_texcoord; varying vec2 v_texcoord;
varying vec2 v_screencord; varying vec2 v_screencord;
uniform vec2 screenOffset;
void main() { void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); 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_screencord = (proj * vec3(pos + screenOffset, 1.0)).xy / 2.0 + vec2(0.5, 0.5); // transform to texture coords
v_texcoord = texcoord; v_texcoord = texcoord;
} }
)#"; )#";

View file

@ -138,7 +138,7 @@ 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, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor) { void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset) {
TRACY_GPU_ZONE("RenderDynamicCursor"); TRACY_GPU_ZONE("RenderDynamicCursor");
alpha = std::clamp(alpha, 0.f, 1.f); alpha = std::clamp(alpha, 0.f, 1.f);
@ -189,6 +189,8 @@ void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox,
wlr_matrix_transpose(glMatrix, glMatrix); wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif #endif
glUniform2f(shader->screenOffset, screenOffset.x, screenOffset.y);
glUniform1i(shader->backgroundTex, 0); glUniform1i(shader->backgroundTex, 0);
glUniform1i(shader->cursorTex, 1); glUniform1i(shader->cursorTex, 1);
glUniform1f(shader->alpha, alpha); glUniform1f(shader->alpha, alpha);

View file

@ -2,5 +2,5 @@
#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, Vector2D hotspot, bool nearest); void renderCursorTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest);
void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor); void renderCursorTextureInternalWithDamageInverted(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, Vector2D hotspot, bool nearest, int mode, bool chroma, CColor chromaColor, Vector2D screenOffset);
void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9], Vector2D hotspot); void projectCursorBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9], Vector2D hotspot);