core: implement fractional scaling support

Additionally, adds --quiet, --verbose.
This commit is contained in:
Vaxry 2024-09-29 18:12:50 +01:00
parent c9238d39f6
commit ed3f644af7
7 changed files with 102 additions and 46 deletions

View file

@ -8,6 +8,12 @@
void Debug::log(LogLevel level, const char* fmt, ...) {
std::string levelstr = "";
if (quiet && (level != ERR && level != CRIT))
return;
if (!verbose && level == TRACE)
return;
switch (level) {
case LOG: levelstr = "[LOG] "; break;
case WARN: levelstr = "[WARN] "; break;

View file

@ -9,9 +9,11 @@ enum LogLevel {
WARN,
ERR,
CRIT,
INFO
INFO,
TRACE,
};
namespace Debug {
void log(LogLevel level, const char* fmt, ...);
inline bool quiet = false, verbose = false;
void log(LogLevel level, const char* fmt, ...);
};

View file

@ -13,6 +13,17 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
return;
}
if (!g_pHyprpicker->m_bNoFractional) {
pViewport = makeShared<CCWpViewport>(g_pHyprpicker->m_pViewporter->sendGetViewport(pSurface->resource()));
// this will not actually be used, as we assume we'll be fullscreen and we can get the real dimensions from screencopy, but we'll have
// this for if we need it in the future
pFractionalScale = makeShared<CCWpFractionalScaleV1>(g_pHyprpicker->m_pFractionalMgr->sendGetFractionalScale(pSurface->resource()));
pFractionalScale->setPreferredScale([this](CCWpFractionalScaleV1* r, uint32_t scale120) { //
Debug::log(TRACE, "Received a preferredScale for %s: %.2f", m_pMonitor->name.c_str(), scale120 / 120.F);
});
}
pLayerSurface = makeShared<CCZwlrLayerSurfaceV1>(
g_pHyprpicker->m_pLayerShell->sendGetLayerSurface(pSurface->resource(), pMonitor->output->resource(), ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "hyprpicker"));
@ -62,8 +73,15 @@ void CLayerSurface::sendFrame() {
frameCallback = makeShared<CCWlCallback>(pSurface->sendFrame());
frameCallback->setDone([this](CCWlCallback* r, uint32_t when) { onCallbackDone(this, when); });
pSurface->sendAttach(lastBuffer == 0 ? buffers[0]->buffer.get() : buffers[1]->buffer.get(), 0, 0);
pSurface->sendSetBufferScale(m_pMonitor->scale);
const auto& PBUFFER = lastBuffer == 0 ? buffers[0] : buffers[1];
pSurface->sendAttach(PBUFFER->buffer.get(), 0, 0);
if (!g_pHyprpicker->m_bNoFractional) {
pSurface->sendSetBufferScale(1);
pViewport->sendSetDestination(m_pMonitor->size.x, m_pMonitor->size.y);
} else
pSurface->sendSetBufferScale(m_pMonitor->scale);
pSurface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF);
pSurface->sendCommit();

View file

@ -10,28 +10,30 @@ class CLayerSurface {
CLayerSurface(SMonitor*);
~CLayerSurface();
void sendFrame();
void markDirty();
void sendFrame();
void markDirty();
SMonitor* m_pMonitor = nullptr;
SMonitor* m_pMonitor = nullptr;
SP<CCZwlrLayerSurfaceV1> pLayerSurface = nullptr;
SP<CCWlSurface> pSurface = nullptr;
SP<CCZwlrLayerSurfaceV1> pLayerSurface = nullptr;
SP<CCWlSurface> pSurface = nullptr;
SP<CCWpViewport> pViewport = nullptr;
SP<CCWpFractionalScaleV1> pFractionalScale = nullptr;
bool wantsACK = false;
uint32_t ACKSerial = 0;
bool working = false;
bool wantsACK = false;
uint32_t ACKSerial = 0;
bool working = false;
int lastBuffer = 0;
SP<SPoolBuffer> buffers[2];
int lastBuffer = 0;
SP<SPoolBuffer> buffers[2];
SP<SPoolBuffer> screenBuffer;
uint32_t scflags = 0;
uint32_t screenBufferFormat = 0;
SP<SPoolBuffer> screenBuffer;
uint32_t scflags = 0;
uint32_t screenBufferFormat = 0;
bool dirty = true;
bool dirty = true;
bool rendered = false;
bool rendered = false;
SP<CCWlCallback> frameCallback = nullptr;
SP<CCWlCallback> frameCallback = nullptr;
};

View file

@ -70,6 +70,11 @@ void CHyprpicker::init() {
} else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
m_pCursorShapeMgr =
makeShared<CCWpCursorShapeManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_cursor_shape_manager_v1_interface, 1));
} else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) {
m_pFractionalMgr =
makeShared<CCWpFractionalScaleManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_fractional_scale_manager_v1_interface, 1));
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
m_pViewporter = makeShared<CCWpViewporter>((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_viewporter_interface, 1));
}
});
@ -83,6 +88,15 @@ void CHyprpicker::init() {
exit(1);
}
if (!m_pFractionalMgr) {
Debug::log(WARN, "wp_fractional_scale_v1 not supported, fractional scaling won't work");
m_bNoFractional = true;
}
if (!m_pViewporter) {
Debug::log(WARN, "wp_viewporter not supported, fractional scaling won't work");
m_bNoFractional = true;
}
for (auto& m : m_vMonitors) {
m_vLayerSurfaces.emplace_back(std::make_unique<CLayerSurface>(m.get()));
@ -121,6 +135,8 @@ void CHyprpicker::finish(int code) {
m_pSeat.reset();
m_pKeyboard.reset();
m_pPointer.reset();
m_pViewporter.reset();
m_pFractionalMgr.reset();
wl_display_disconnect(m_pWLDisplay);
m_pWLDisplay = nullptr;
@ -135,9 +151,11 @@ void CHyprpicker::recheckACK() {
ls->wantsACK = false;
ls->pLayerSurface->sendAckConfigure(ls->ACKSerial);
if (!ls->buffers[0] || ls->buffers[0]->pixelSize != ls->m_pMonitor->size * ls->m_pMonitor->scale) {
ls->buffers[0] = makeShared<SPoolBuffer>(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4);
ls->buffers[1] = makeShared<SPoolBuffer>(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4);
const auto MONITORSIZE = ls->screenBuffer && !g_pHyprpicker->m_bNoFractional ? ls->screenBuffer->pixelSize : ls->m_pMonitor->size * ls->m_pMonitor->scale;
if (!ls->buffers[0] || ls->buffers[0]->pixelSize != MONITORSIZE) {
ls->buffers[0] = makeShared<SPoolBuffer>(MONITORSIZE, WL_SHM_FORMAT_ARGB8888, MONITORSIZE.x * 4);
ls->buffers[1] = makeShared<SPoolBuffer>(MONITORSIZE, WL_SHM_FORMAT_ARGB8888, MONITORSIZE.x * 4);
}
}
}
@ -323,8 +341,8 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
return;
}
PBUFFER->surface = cairo_image_surface_create_for_data((unsigned char*)PBUFFER->data, CAIRO_FORMAT_ARGB32, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale,
pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale, PBUFFER->pixelSize.x * 4);
PBUFFER->surface =
cairo_image_surface_create_for_data((unsigned char*)PBUFFER->data, CAIRO_FORMAT_ARGB32, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y, PBUFFER->pixelSize.x * 4);
PBUFFER->cairo = cairo_create(PBUFFER->surface);
@ -334,15 +352,13 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0);
cairo_rectangle(PCAIRO, 0, 0, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale, pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale);
cairo_rectangle(PCAIRO, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y);
cairo_fill(PCAIRO);
if (pSurface == g_pHyprpicker->m_pLastSurface && !forceInactive) {
const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize;
const auto SCALECURSOR = Vector2D{
g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale),
g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.y / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.y / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale)};
const auto CLICKPOS = Vector2D{g_pHyprpicker->m_vLastCoords.floor().x * SCALECURSOR.x, g_pHyprpicker->m_vLastCoords.floor().y * SCALECURSOR.y};
if (pSurface == m_pLastSurface && !forceInactive) {
const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize;
const auto MOUSECOORDSABS = m_vLastCoords.floor() / pSurface->m_pMonitor->size;
const auto CLICKPOS = MOUSECOORDSABS * PBUFFER->pixelSize;
const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface);
cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR);
@ -368,15 +384,17 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
//
cairo_restore(PCAIRO);
if (!g_pHyprpicker->m_bNoZoom) {
if (!m_bNoZoom) {
cairo_save(PCAIRO);
const auto PIXCOLOR = getColorFromPixel(pSurface, CLICKPOS);
const auto CLICKPOSBUF = CLICKPOS / PBUFFER->pixelSize * pSurface->screenBuffer->pixelSize;
const auto PIXCOLOR = getColorFromPixel(pSurface, CLICKPOSBUF);
cairo_set_source_rgba(PCAIRO, PIXCOLOR.r / 255.f, PIXCOLOR.g / 255.f, PIXCOLOR.b / 255.f, PIXCOLOR.a / 255.f);
cairo_scale(PCAIRO, 1, 1);
cairo_arc(PCAIRO, m_vLastCoords.x * pSurface->m_pMonitor->scale, m_vLastCoords.y * pSurface->m_pMonitor->scale, 105 / SCALEBUFS.x, 0, 2 * M_PI);
cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, 105 / SCALEBUFS.x, 0, 2 * M_PI);
cairo_clip(PCAIRO);
cairo_fill(PCAIRO);
@ -391,12 +409,12 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
cairo_pattern_set_filter(PATTERN, CAIRO_FILTER_NEAREST);
cairo_matrix_t matrix;
cairo_matrix_init_identity(&matrix);
cairo_matrix_translate(&matrix, CLICKPOS.x + 0.5f, CLICKPOS.y + 0.5f);
cairo_matrix_translate(&matrix, CLICKPOSBUF.x + 0.5f, CLICKPOSBUF.y + 0.5f);
cairo_matrix_scale(&matrix, 0.1f, 0.1f);
cairo_matrix_translate(&matrix, -CLICKPOS.x / SCALEBUFS.x - 0.5f, -CLICKPOS.y / SCALEBUFS.y - 0.5f);
cairo_matrix_translate(&matrix, -CLICKPOSBUF.x / SCALEBUFS.x - 0.5f, -CLICKPOSBUF.y / SCALEBUFS.y - 0.5f);
cairo_pattern_set_matrix(PATTERN, &matrix);
cairo_set_source(PCAIRO, PATTERN);
cairo_arc(PCAIRO, m_vLastCoords.x * pSurface->m_pMonitor->scale, m_vLastCoords.y * pSurface->m_pMonitor->scale, 100 / SCALEBUFS.x, 0, 2 * M_PI);
cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, 100 / SCALEBUFS.x, 0, 2 * M_PI);
cairo_clip(PCAIRO);
cairo_paint(PCAIRO);
@ -406,10 +424,10 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
cairo_pattern_destroy(PATTERN);
}
} else if (!g_pHyprpicker->m_bRenderInactive) {
} else if (!m_bRenderInactive) {
cairo_set_operator(PCAIRO, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0);
cairo_rectangle(PCAIRO, 0, 0, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale, pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale);
cairo_rectangle(PCAIRO, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y);
cairo_fill(PCAIRO);
} else {
const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize;
@ -537,10 +555,8 @@ void CHyprpicker::initMouse() {
const auto FLUMI = [](const float& c) -> float { return c <= 0.03928 ? c / 12.92 : powf((c + 0.055) / 1.055, 2.4); };
// get the px and print it
const auto SCALE = Vector2D{m_pLastSurface->screenBuffer->pixelSize.x / (m_pLastSurface->buffers[0]->pixelSize.x / m_pLastSurface->m_pMonitor->scale),
m_pLastSurface->screenBuffer->pixelSize.y / (m_pLastSurface->buffers[0]->pixelSize.y / m_pLastSurface->m_pMonitor->scale)};
const auto CLICKPOS = m_vLastCoords.floor() * SCALE;
const auto MOUSECOORDSABS = m_vLastCoords.floor() / m_pLastSurface->m_pMonitor->size;
const auto CLICKPOS = MOUSECOORDSABS * m_pLastSurface->screenBuffer->pixelSize;
const auto COL = getColorFromPixel(m_pLastSurface, CLICKPOS);

View file

@ -28,6 +28,8 @@ class CHyprpicker {
SP<CCWlSeat> m_pSeat;
SP<CCWlKeyboard> m_pKeyboard;
SP<CCWlPointer> m_pPointer;
SP<CCWpFractionalScaleManagerV1> m_pFractionalMgr;
SP<CCWpViewporter> m_pViewporter;
wl_display* m_pWLDisplay = nullptr;
xkb_context* m_pXKBContext = nullptr;
@ -41,6 +43,7 @@ class CHyprpicker {
bool m_bAutoCopy = false;
bool m_bRenderInactive = false;
bool m_bNoZoom = false;
bool m_bNoFractional = false;
bool m_bRunning = true;

View file

@ -11,7 +11,10 @@ static void help(void) {
<< " -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n"
<< " -h | --help | Show this help message\n"
<< " -r | --render-inactive | Render (freeze) inactive displays\n"
<< " -z | --no-zoom | Disable the zoom lens\n";
<< " -z | --no-zoom | Disable the zoom lens\n"
<< " -q | --quiet | Disable most logs (leaves errors)\n"
<< " -v | --verbose | Enable more logs\n"
<< " -t | --no-fractional | Disable fractional scaling support\n";
}
int main(int argc, char** argv, char** envp) {
@ -25,9 +28,12 @@ int main(int argc, char** argv, char** envp) {
{"no-fancy", no_argument, NULL, 'n'},
{"render-inactive", no_argument, NULL, 'r'},
{"no-zoom", no_argument, NULL, 'z'},
{"no-fractional", no_argument, NULL, 't'},
{"quiet", no_argument, NULL, 'q'},
{"verbose", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}};
int c = getopt_long(argc, argv, ":f:hnarz", long_options, &option_index);
int c = getopt_long(argc, argv, ":f:hnarzqvt", long_options, &option_index);
if (c == -1)
break;
@ -53,6 +59,9 @@ int main(int argc, char** argv, char** envp) {
case 'a': g_pHyprpicker->m_bAutoCopy = true; break;
case 'r': g_pHyprpicker->m_bRenderInactive = true; break;
case 'z': g_pHyprpicker->m_bNoZoom = true; break;
case 't': g_pHyprpicker->m_bNoFractional = true; break;
case 'q': Debug::quiet = true; break;
case 'v': Debug::verbose = true; break;
default: help(); exit(1);
}