From 03bc27be945a2c83f5b8089ae03030e10f56e371 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Fri, 4 Aug 2023 20:41:30 +0200 Subject: [PATCH] internal: transform received screencopy buffer --- src/events/Events.cpp | 100 ++++++++++++++++++++++++++++++++--- src/helpers/LayerSurface.hpp | 35 ++++++------ src/helpers/Monitor.hpp | 13 ++--- src/hyprpicker.cpp | 25 ++------- src/hyprpicker.hpp | 1 + 5 files changed, 123 insertions(+), 51 deletions(-) diff --git a/src/events/Events.cpp b/src/events/Events.cpp index 6c1828d..3e81901 100644 --- a/src/events/Events.cpp +++ b/src/events/Events.cpp @@ -4,7 +4,9 @@ void Events::geometry(void* data, wl_output* output, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char* make, const char* model, int32_t transform) { - // ignored + const auto PMONITOR = (SMonitor*)data; + + PMONITOR->transform = (wl_output_transform)transform; } void Events::mode(void* data, wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { @@ -38,9 +40,10 @@ void Events::ls_configure(void* data, zwlr_layer_surface_v1* surface, uint32_t s const auto PLAYERSURFACE = (CLayerSurface*)data; PLAYERSURFACE->m_pMonitor->size = Vector2D(width, height); - PLAYERSURFACE->ACKSerial = serial; - PLAYERSURFACE->wantsACK = true; - PLAYERSURFACE->working = true; + + PLAYERSURFACE->ACKSerial = serial; + PLAYERSURFACE->wantsACK = true; + PLAYERSURFACE->working = true; g_pHyprpicker->recheckACK(); } @@ -276,6 +279,8 @@ void Events::handleBufferRelease(void* data, struct wl_buffer* wl_buffer) { void Events::handleSCBuffer(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { const auto PLS = (CLayerSurface*)data; + PLS->screenBufferFormat = format; + if (!PLS->screenBuffer.buffer) g_pHyprpicker->createBuffer(&PLS->screenBuffer, width, height, format, stride); @@ -288,12 +293,91 @@ void Events::handleSCFlags(void* data, struct zwlr_screencopy_frame_v1* frame, u PLS->scflags = flags; g_pHyprpicker->recheckACK(); - - g_pHyprpicker->renderSurface(PLS); } -void Events::handleSCReady(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { - // ignore +void Events::handleSCReady(void* lsdata, struct zwlr_screencopy_frame_v1* frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { + const auto PLS = (CLayerSurface*)lsdata; + + SPoolBuffer newBuf; + Vector2D transformedSize = PLS->screenBuffer.pixelSize; + + if (PLS->m_pMonitor->transform % 2 == 1) + std::swap(transformedSize.x, transformedSize.y); + + g_pHyprpicker->createBuffer(&newBuf, transformedSize.x, transformedSize.y, PLS->screenBufferFormat, transformedSize.x * 4); + + int bytesPerPixel = PLS->screenBuffer.stride / (int)PLS->screenBuffer.pixelSize.x; + void* data = PLS->screenBuffer.data; + if (bytesPerPixel == 4) + g_pHyprpicker->convertBuffer(&PLS->screenBuffer); + else if (bytesPerPixel == 3) { + Debug::log(WARN, "24 bit formats are unsupported, hyprpicker may or may not work as intended!"); + data = g_pHyprpicker->convert24To32Buffer(&PLS->screenBuffer); + PLS->screenBuffer.paddedData = data; + } else { + Debug::log(CRIT, "Unsupported stride/bytes per pixel %i", bytesPerPixel); + g_pHyprpicker->finish(1); + } + + cairo_surface_t* oldSurface = cairo_image_surface_create_for_data((unsigned char*)data, CAIRO_FORMAT_ARGB32, PLS->screenBuffer.pixelSize.x, PLS->screenBuffer.pixelSize.y, + PLS->screenBuffer.pixelSize.x * 4); + + cairo_surface_flush(oldSurface); + + newBuf.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, transformedSize.x, transformedSize.y); + + const auto PCAIRO = cairo_create(newBuf.surface); + + auto cairoTransformMtx = [&](cairo_matrix_t* mtx) -> void { + const auto TR = PLS->m_pMonitor->transform % 4; + + if (TR == 0) + return; + + const auto TRFLIP = PLS->m_pMonitor->transform >= 4; + + cairo_matrix_rotate(mtx, -M_PI_2 * (double)TR); + + if (TR == 1) + cairo_matrix_translate(mtx, -transformedSize.x, 0); + else if (TR == 2) + cairo_matrix_translate(mtx, -transformedSize.x, -transformedSize.y); + else if (TR == 3) + cairo_matrix_translate(mtx, 0, -transformedSize.y); + + // TODO: flipped + }; + + cairo_save(PCAIRO); + + cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); + + cairo_rectangle(PCAIRO, 0, 0, 0xFFFF, 0xFFFF); + cairo_fill(PCAIRO); + + const auto PATTERNPRE = cairo_pattern_create_for_surface(oldSurface); + cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); + cairo_matrix_t matrixPre; + cairo_matrix_init_identity(&matrixPre); + cairo_matrix_scale(&matrixPre, 1.0, 1.0); + cairoTransformMtx(&matrixPre); + cairo_pattern_set_matrix(PATTERNPRE, &matrixPre); + cairo_set_source(PCAIRO, PATTERNPRE); + cairo_paint(PCAIRO); + + cairo_surface_flush(newBuf.surface); + + cairo_pattern_destroy(PATTERNPRE); + + cairo_destroy(PCAIRO); + + cairo_surface_destroy(oldSurface); + + g_pHyprpicker->destroyBuffer(&PLS->screenBuffer); + + PLS->screenBuffer = newBuf; + + g_pHyprpicker->renderSurface(PLS); } void Events::handleSCFailed(void* data, struct zwlr_screencopy_frame_v1* frame) { diff --git a/src/helpers/LayerSurface.hpp b/src/helpers/LayerSurface.hpp index 6a86c87..98f47ca 100644 --- a/src/helpers/LayerSurface.hpp +++ b/src/helpers/LayerSurface.hpp @@ -6,31 +6,32 @@ struct SMonitor; class CLayerSurface { -public: + public: CLayerSurface(SMonitor*); ~CLayerSurface(); - SMonitor* m_pMonitor = nullptr; + SMonitor* m_pMonitor = nullptr; - zwlr_layer_surface_v1* pLayerSurface = nullptr; - wl_surface* pSurface = nullptr; - wl_surface* pCursorSurface = nullptr; + zwlr_layer_surface_v1* pLayerSurface = nullptr; + wl_surface* pSurface = nullptr; + wl_surface* pCursorSurface = nullptr; - bool wantsACK = false; - uint32_t ACKSerial = 0; - bool working = false; + bool wantsACK = false; + uint32_t ACKSerial = 0; + bool working = false; - int lastBuffer = 0; - SPoolBuffer buffers[2]; - - SPoolBuffer screenBuffer; - uint32_t scflags = 0; + int lastBuffer = 0; + SPoolBuffer buffers[2]; - bool dirty = true; + SPoolBuffer screenBuffer; + uint32_t scflags = 0; + uint32_t screenBufferFormat = 0; - bool rendered = false; + bool dirty = true; - wl_callback* frame_callback = nullptr; + bool rendered = false; - wl_cursor_image* pCursorImg = nullptr; + wl_callback* frame_callback = nullptr; + + wl_cursor_image* pCursorImg = nullptr; }; \ No newline at end of file diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 48583f2..9587b5b 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -3,13 +3,14 @@ #include "../defines.hpp" struct SMonitor { - std::string name = ""; - wl_output* output = nullptr; - uint32_t wayland_name = 0; - Vector2D size; - int scale; + std::string name = ""; + wl_output* output = nullptr; + uint32_t wayland_name = 0; + Vector2D size; + int scale; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - bool ready = false; + bool ready = false; zwlr_screencopy_frame_v1* pSCFrame = nullptr; }; \ No newline at end of file diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index fd9007d..6c3d0d9 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -238,7 +238,7 @@ void CHyprpicker::convertBuffer(SPoolBuffer* pBuffer) { } // Mallocs a new buffer, which needs to be free'd! -void* convert24To32Buffer(SPoolBuffer* pBuffer) { +void* CHyprpicker::convert24To32Buffer(SPoolBuffer* pBuffer) { uint8_t* newBuffer = (uint8_t*)malloc((size_t)pBuffer->pixelSize.x * pBuffer->pixelSize.y * 4); int newBufferStride = pBuffer->pixelSize.x * 4; uint8_t* oldBuffer = (uint8_t*)pBuffer->data; @@ -298,32 +298,17 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { if (!PBUFFER || !pSurface->screenBuffer.buffer) return; - if (!pSurface->screenBuffer.surface) { - int bytesPerPixel = pSurface->screenBuffer.stride / (int)pSurface->screenBuffer.pixelSize.x; - void* data = pSurface->screenBuffer.data; - if (bytesPerPixel == 4) { - convertBuffer(&pSurface->screenBuffer); - } else if (bytesPerPixel == 3) { - Debug::log(WARN, "24 bit formats are unsupported, hyprpicker may or may not work as intended!"); - data = convert24To32Buffer(&pSurface->screenBuffer); - pSurface->screenBuffer.paddedData = data; - } else { - Debug::log(CRIT, "Unsupported stride/bytes per pixel %i", bytesPerPixel); - g_pHyprpicker->finish(1); - } - pSurface->screenBuffer.surface = cairo_image_surface_create_for_data((unsigned char*)data, CAIRO_FORMAT_ARGB32, pSurface->screenBuffer.pixelSize.x, - pSurface->screenBuffer.pixelSize.y, pSurface->screenBuffer.pixelSize.x * 4); - } - 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->cairo = cairo_create(PBUFFER->surface); + + PBUFFER->cairo = cairo_create(PBUFFER->surface); const auto PCAIRO = PBUFFER->cairo; cairo_save(PCAIRO); 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_fill(PCAIRO); @@ -433,7 +418,7 @@ void CHyprpicker::sendFrame(CLayerSurface* pSurface) { wl_surface_attach(pSurface->pSurface, pSurface->lastBuffer == 0 ? pSurface->buffers[0].buffer : pSurface->buffers[1].buffer, 0, 0); wl_surface_set_buffer_scale(pSurface->pSurface, pSurface->m_pMonitor->scale); - wl_surface_damage_buffer(pSurface->pSurface, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_damage_buffer(pSurface->pSurface, 0, 0, 0xFFFF, 0xFFFF); wl_surface_commit(pSurface->pSurface); pSurface->dirty = false; diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 214b9dc..17fd15c 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -58,6 +58,7 @@ class CHyprpicker { SPoolBuffer* getBufferForLS(CLayerSurface*); void convertBuffer(SPoolBuffer*); + void* convert24To32Buffer(SPoolBuffer*); void markDirty();