internal: transform received screencopy buffer

This commit is contained in:
vaxerski 2023-08-04 20:41:30 +02:00
parent 0889bd5f6f
commit 03bc27be94
5 changed files with 123 additions and 51 deletions

View file

@ -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,6 +40,7 @@ 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;
@ -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) {

View file

@ -25,6 +25,7 @@ public:
SPoolBuffer screenBuffer;
uint32_t scflags = 0;
uint32_t screenBufferFormat = 0;
bool dirty = true;

View file

@ -8,6 +8,7 @@ struct SMonitor {
uint32_t wayland_name = 0;
Vector2D size;
int scale;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool ready = false;

View file

@ -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,25 +298,9 @@ 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);
const auto PCAIRO = PBUFFER->cairo;
@ -324,6 +308,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
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;

View file

@ -58,6 +58,7 @@ class CHyprpicker {
SPoolBuffer* getBufferForLS(CLayerSurface*);
void convertBuffer(SPoolBuffer*);
void* convert24To32Buffer(SPoolBuffer*);
void markDirty();