mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-16 23:05:58 +01:00
background: add screenshot
This commit is contained in:
parent
3b7e055dcf
commit
2836f02ded
11 changed files with 779 additions and 17 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
protocols/
|
protocols/*.h
|
||||||
|
protocols/*.c
|
|
@ -33,7 +33,7 @@ message(STATUS "Checking deps...")
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols wayland-egl hyprlang>=0.4.0 egl opengl xkbcommon cairo pangocairo pam)
|
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols wayland-egl hyprlang>=0.4.0 egl opengl xkbcommon cairo pangocairo pam libdrm gbm)
|
||||||
|
|
||||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||||
add_executable(hyprlock ${SRCFILES})
|
add_executable(hyprlock ${SRCFILES})
|
||||||
|
@ -75,6 +75,8 @@ protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
|
||||||
protocol("unstable/tablet/tablet-unstable-v2.xml" "tablet-unstable-v2" false)
|
protocol("unstable/tablet/tablet-unstable-v2.xml" "tablet-unstable-v2" false)
|
||||||
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
|
||||||
protocol("stable/viewporter/viewporter.xml" "viewporter" false)
|
protocol("stable/viewporter/viewporter.xml" "viewporter" false)
|
||||||
|
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
|
||||||
|
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
install(TARGETS hyprlock)
|
install(TARGETS hyprlock)
|
||||||
|
|
232
protocols/wlr-screencopy-unstable-v1.xml
Normal file
232
protocols/wlr-screencopy-unstable-v1.xml
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_screencopy_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2018 Simon Ser
|
||||||
|
Copyright © 2019 Andri Yngvason
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="screen content capturing on client buffers">
|
||||||
|
This protocol allows clients to ask the compositor to copy part of the
|
||||||
|
screen content to a client buffer.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
|
may be added together with the corresponding interface version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version number in
|
||||||
|
the protocol and interface names and resetting the interface version.
|
||||||
|
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||||
|
version number in the protocol and interface names are removed and the
|
||||||
|
interface version number is reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwlr_screencopy_manager_v1" version="3">
|
||||||
|
<description summary="manager to inform clients and begin capturing">
|
||||||
|
This object is a manager which offers requests to start capturing from a
|
||||||
|
source.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="capture_output">
|
||||||
|
<description summary="capture an output">
|
||||||
|
Capture the next frame of an entire output.
|
||||||
|
</description>
|
||||||
|
<arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/>
|
||||||
|
<arg name="overlay_cursor" type="int"
|
||||||
|
summary="composite cursor onto the frame"/>
|
||||||
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="capture_output_region">
|
||||||
|
<description summary="capture an output's region">
|
||||||
|
Capture the next frame of an output's region.
|
||||||
|
|
||||||
|
The region is given in output logical coordinates, see
|
||||||
|
xdg_output.logical_size. The region will be clipped to the output's
|
||||||
|
extents.
|
||||||
|
</description>
|
||||||
|
<arg name="frame" type="new_id" interface="zwlr_screencopy_frame_v1"/>
|
||||||
|
<arg name="overlay_cursor" type="int"
|
||||||
|
summary="composite cursor onto the frame"/>
|
||||||
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
|
<arg name="x" type="int"/>
|
||||||
|
<arg name="y" type="int"/>
|
||||||
|
<arg name="width" type="int"/>
|
||||||
|
<arg name="height" type="int"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the manager">
|
||||||
|
All objects created by the manager will still remain valid, until their
|
||||||
|
appropriate destroy request has been called.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_screencopy_frame_v1" version="3">
|
||||||
|
<description summary="a frame ready for copy">
|
||||||
|
This object represents a single frame.
|
||||||
|
|
||||||
|
When created, a series of buffer events will be sent, each representing a
|
||||||
|
supported buffer type. The "buffer_done" event is sent afterwards to
|
||||||
|
indicate that all supported buffer types have been enumerated. The client
|
||||||
|
will then be able to send a "copy" request. If the capture is successful,
|
||||||
|
the compositor will send a "flags" followed by a "ready" event.
|
||||||
|
|
||||||
|
For objects version 2 or lower, wl_shm buffers are always supported, ie.
|
||||||
|
the "buffer" event is guaranteed to be sent.
|
||||||
|
|
||||||
|
If the capture failed, the "failed" event is sent. This can happen anytime
|
||||||
|
before the "ready" event.
|
||||||
|
|
||||||
|
Once either a "ready" or a "failed" event is received, the client should
|
||||||
|
destroy the frame.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="buffer">
|
||||||
|
<description summary="wl_shm buffer information">
|
||||||
|
Provides information about wl_shm buffer parameters that need to be
|
||||||
|
used for this frame. This event is sent once after the frame is created
|
||||||
|
if wl_shm buffers are supported.
|
||||||
|
</description>
|
||||||
|
<arg name="format" type="uint" enum="wl_shm.format" summary="buffer format"/>
|
||||||
|
<arg name="width" type="uint" summary="buffer width"/>
|
||||||
|
<arg name="height" type="uint" summary="buffer height"/>
|
||||||
|
<arg name="stride" type="uint" summary="buffer stride"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="copy">
|
||||||
|
<description summary="copy the frame">
|
||||||
|
Copy the frame to the supplied buffer. The buffer must have a the
|
||||||
|
correct size, see zwlr_screencopy_frame_v1.buffer and
|
||||||
|
zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a
|
||||||
|
supported format.
|
||||||
|
|
||||||
|
If the frame is successfully copied, a "flags" and a "ready" events are
|
||||||
|
sent. Otherwise, a "failed" event is sent.
|
||||||
|
</description>
|
||||||
|
<arg name="buffer" type="object" interface="wl_buffer"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_used" value="0"
|
||||||
|
summary="the object has already been used to copy a wl_buffer"/>
|
||||||
|
<entry name="invalid_buffer" value="1"
|
||||||
|
summary="buffer attributes are invalid"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="flags" bitfield="true">
|
||||||
|
<entry name="y_invert" value="1" summary="contents are y-inverted"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<event name="flags">
|
||||||
|
<description summary="frame flags">
|
||||||
|
Provides flags about the frame. This event is sent once before the
|
||||||
|
"ready" event.
|
||||||
|
</description>
|
||||||
|
<arg name="flags" type="uint" enum="flags" summary="frame flags"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="ready">
|
||||||
|
<description summary="indicates frame is available for reading">
|
||||||
|
Called as soon as the frame is copied, indicating it is available
|
||||||
|
for reading. This event includes the time at which presentation happened
|
||||||
|
at.
|
||||||
|
|
||||||
|
The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
|
||||||
|
each component being an unsigned 32-bit value. Whole seconds are in
|
||||||
|
tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo,
|
||||||
|
and the additional fractional part in tv_nsec as nanoseconds. Hence,
|
||||||
|
for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part
|
||||||
|
may have an arbitrary offset at start.
|
||||||
|
|
||||||
|
After receiving this event, the client should destroy the object.
|
||||||
|
</description>
|
||||||
|
<arg name="tv_sec_hi" type="uint"
|
||||||
|
summary="high 32 bits of the seconds part of the timestamp"/>
|
||||||
|
<arg name="tv_sec_lo" type="uint"
|
||||||
|
summary="low 32 bits of the seconds part of the timestamp"/>
|
||||||
|
<arg name="tv_nsec" type="uint"
|
||||||
|
summary="nanoseconds part of the timestamp"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="failed">
|
||||||
|
<description summary="frame copy failed">
|
||||||
|
This event indicates that the attempted frame copy has failed.
|
||||||
|
|
||||||
|
After receiving this event, the client should destroy the object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="delete this object, used or not">
|
||||||
|
Destroys the frame. This request can be sent at any time by the client.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<!-- Version 2 additions -->
|
||||||
|
<request name="copy_with_damage" since="2">
|
||||||
|
<description summary="copy the frame when it's damaged">
|
||||||
|
Same as copy, except it waits until there is damage to copy.
|
||||||
|
</description>
|
||||||
|
<arg name="buffer" type="object" interface="wl_buffer"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="damage" since="2">
|
||||||
|
<description summary="carries the coordinates of the damaged region">
|
||||||
|
This event is sent right before the ready event when copy_with_damage is
|
||||||
|
requested. It may be generated multiple times for each copy_with_damage
|
||||||
|
request.
|
||||||
|
|
||||||
|
The arguments describe a box around an area that has changed since the
|
||||||
|
last copy request that was derived from the current screencopy manager
|
||||||
|
instance.
|
||||||
|
|
||||||
|
The union of all regions received between the call to copy_with_damage
|
||||||
|
and a ready event is the total damage since the prior ready event.
|
||||||
|
</description>
|
||||||
|
<arg name="x" type="uint" summary="damaged x coordinates"/>
|
||||||
|
<arg name="y" type="uint" summary="damaged y coordinates"/>
|
||||||
|
<arg name="width" type="uint" summary="current width"/>
|
||||||
|
<arg name="height" type="uint" summary="current height"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<!-- Version 3 additions -->
|
||||||
|
<event name="linux_dmabuf" since="3">
|
||||||
|
<description summary="linux-dmabuf buffer information">
|
||||||
|
Provides information about linux-dmabuf buffer parameters that need to
|
||||||
|
be used for this frame. This event is sent once after the frame is
|
||||||
|
created if linux-dmabuf buffers are supported.
|
||||||
|
</description>
|
||||||
|
<arg name="format" type="uint" summary="fourcc pixel format"/>
|
||||||
|
<arg name="width" type="uint" summary="buffer width"/>
|
||||||
|
<arg name="height" type="uint" summary="buffer height"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="buffer_done" since="3">
|
||||||
|
<description summary="all buffer types reported">
|
||||||
|
This event is sent once after all buffer events have been sent.
|
||||||
|
|
||||||
|
The client should proceed to create a buffer of one of the supported
|
||||||
|
types, and send a "copy" request.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
|
@ -10,6 +10,9 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
|
|
||||||
CHyprlock::CHyprlock(const std::string& wlDisplay) {
|
CHyprlock::CHyprlock(const std::string& wlDisplay) {
|
||||||
m_sWaylandState.display = wl_display_connect(wlDisplay.empty() ? nullptr : wlDisplay.c_str());
|
m_sWaylandState.display = wl_display_connect(wlDisplay.empty() ? nullptr : wlDisplay.c_str());
|
||||||
|
@ -24,8 +27,6 @@ CHyprlock::CHyprlock(const std::string& wlDisplay) {
|
||||||
if (!m_pXKBContext)
|
if (!m_pXKBContext)
|
||||||
Debug::log(ERR, "Failed to create xkb context");
|
Debug::log(ERR, "Failed to create xkb context");
|
||||||
|
|
||||||
g_pRenderer = std::make_unique<CRenderer>();
|
|
||||||
|
|
||||||
const auto GRACE = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:grace");
|
const auto GRACE = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:grace");
|
||||||
m_tGraceEnds = **GRACE ? std::chrono::system_clock::now() + std::chrono::seconds(**GRACE) : std::chrono::system_clock::from_time_t(0);
|
m_tGraceEnds = **GRACE ? std::chrono::system_clock::now() + std::chrono::seconds(**GRACE) : std::chrono::system_clock::from_time_t(0);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +43,177 @@ inline const wl_seat_listener seatListener = {
|
||||||
|
|
||||||
// end wl_seat
|
// end wl_seat
|
||||||
|
|
||||||
|
// dmabuf
|
||||||
|
|
||||||
|
static void handleDMABUFFormat(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDMABUFModifier(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) {
|
||||||
|
g_pHyprlock->dma.dmabufMods.push_back({format, (((uint64_t)modifier_hi) << 32) | modifier_lo});
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const zwp_linux_dmabuf_v1_listener dmabufListener = {
|
||||||
|
.format = handleDMABUFFormat,
|
||||||
|
.modifier = handleDMABUFModifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dmabufFeedbackMainDevice(void* data, zwp_linux_dmabuf_feedback_v1* feedback, wl_array* device_arr) {
|
||||||
|
Debug::log(LOG, "[core] dmabufFeedbackMainDevice");
|
||||||
|
|
||||||
|
RASSERT(!g_pHyprlock->dma.gbm, "double dmabuf feedback");
|
||||||
|
|
||||||
|
dev_t device;
|
||||||
|
assert(device_arr->size == sizeof(device));
|
||||||
|
memcpy(&device, device_arr->data, sizeof(device));
|
||||||
|
|
||||||
|
drmDevice* drmDev;
|
||||||
|
if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0) {
|
||||||
|
Debug::log(WARN, "[dmabuf] unable to open main device?");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pHyprlock->dma.gbmDevice = g_pHyprlock->createGBMDevice(drmDev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dmabufFeedbackFormatTable(void* data, zwp_linux_dmabuf_feedback_v1* feedback, int fd, uint32_t size) {
|
||||||
|
Debug::log(TRACE, "[core] dmabufFeedbackFormatTable");
|
||||||
|
|
||||||
|
g_pHyprlock->dma.dmabufMods.clear();
|
||||||
|
|
||||||
|
g_pHyprlock->dma.formatTable = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
|
||||||
|
if (g_pHyprlock->dma.formatTable == MAP_FAILED) {
|
||||||
|
Debug::log(ERR, "[core] format table failed to mmap");
|
||||||
|
g_pHyprlock->dma.formatTable = nullptr;
|
||||||
|
g_pHyprlock->dma.formatTableSize = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pHyprlock->dma.formatTableSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dmabufFeedbackDone(void* data, zwp_linux_dmabuf_feedback_v1* feedback) {
|
||||||
|
Debug::log(TRACE, "[core] dmabufFeedbackDone");
|
||||||
|
|
||||||
|
if (g_pHyprlock->dma.formatTable)
|
||||||
|
munmap(g_pHyprlock->dma.formatTable, g_pHyprlock->dma.formatTableSize);
|
||||||
|
|
||||||
|
g_pHyprlock->dma.formatTable = nullptr;
|
||||||
|
g_pHyprlock->dma.formatTableSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dmabufFeedbackTrancheTargetDevice(void* data, zwp_linux_dmabuf_feedback_v1* feedback, wl_array* device_arr) {
|
||||||
|
Debug::log(TRACE, "[core] dmabufFeedbackTrancheTargetDevice");
|
||||||
|
|
||||||
|
dev_t device;
|
||||||
|
assert(device_arr->size == sizeof(device));
|
||||||
|
memcpy(&device, device_arr->data, sizeof(device));
|
||||||
|
|
||||||
|
drmDevice* drmDev;
|
||||||
|
if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_pHyprlock->dma.gbmDevice) {
|
||||||
|
drmDevice* drmDevRenderer = NULL;
|
||||||
|
drmGetDevice2(gbm_device_get_fd(g_pHyprlock->dma.gbmDevice), /* flags */ 0, &drmDevRenderer);
|
||||||
|
g_pHyprlock->dma.deviceUsed = drmDevicesEqual(drmDevRenderer, drmDev);
|
||||||
|
} else {
|
||||||
|
g_pHyprlock->dma.gbmDevice = g_pHyprlock->createGBMDevice(drmDev);
|
||||||
|
g_pHyprlock->dma.deviceUsed = g_pHyprlock->dma.gbm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dmabufFeedbackTrancheFlags(void* data, zwp_linux_dmabuf_feedback_v1* feedback, uint32_t flags) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dmabufFeedbackTrancheFormats(void* data, zwp_linux_dmabuf_feedback_v1* feedback, wl_array* indices) {
|
||||||
|
Debug::log(TRACE, "[core] dmabufFeedbackTrancheFormats");
|
||||||
|
|
||||||
|
if (!g_pHyprlock->dma.deviceUsed || !g_pHyprlock->dma.formatTable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct fm_entry {
|
||||||
|
uint32_t format;
|
||||||
|
uint32_t padding;
|
||||||
|
uint64_t modifier;
|
||||||
|
};
|
||||||
|
// An entry in the table has to be 16 bytes long
|
||||||
|
assert(sizeof(fm_entry) == 16);
|
||||||
|
|
||||||
|
uint32_t n_modifiers = g_pHyprlock->dma.formatTableSize / sizeof(fm_entry);
|
||||||
|
fm_entry* fm_entry = (struct fm_entry*)g_pHyprlock->dma.formatTable;
|
||||||
|
uint16_t* idx;
|
||||||
|
|
||||||
|
for (idx = (uint16_t*)indices->data; (const char*)idx < (const char*)indices->data + indices->size; idx++) {
|
||||||
|
if (*idx >= n_modifiers)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_pHyprlock->dma.dmabufMods.push_back({(fm_entry + *idx)->format, (fm_entry + *idx)->modifier});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dmabufFeedbackTrancheDone(void* data, struct zwp_linux_dmabuf_feedback_v1* zwp_linux_dmabuf_feedback_v1) {
|
||||||
|
Debug::log(TRACE, "[core] dmabufFeedbackTrancheDone");
|
||||||
|
|
||||||
|
g_pHyprlock->dma.deviceUsed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const zwp_linux_dmabuf_feedback_v1_listener dmabufFeedbackListener = {
|
||||||
|
.done = dmabufFeedbackDone,
|
||||||
|
.format_table = dmabufFeedbackFormatTable,
|
||||||
|
.main_device = dmabufFeedbackMainDevice,
|
||||||
|
.tranche_done = dmabufFeedbackTrancheDone,
|
||||||
|
.tranche_target_device = dmabufFeedbackTrancheTargetDevice,
|
||||||
|
.tranche_formats = dmabufFeedbackTrancheFormats,
|
||||||
|
.tranche_flags = dmabufFeedbackTrancheFlags,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char* gbm_find_render_node(drmDevice* device) {
|
||||||
|
drmDevice* devices[64];
|
||||||
|
char* render_node = NULL;
|
||||||
|
|
||||||
|
int n = drmGetDevices2(0, devices, sizeof(devices) / sizeof(devices[0]));
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
drmDevice* dev = devices[i];
|
||||||
|
if (device && !drmDevicesEqual(device, dev)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(dev->available_nodes & (1 << DRM_NODE_RENDER)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
render_node = strdup(dev->nodes[DRM_NODE_RENDER]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmFreeDevices(devices, n);
|
||||||
|
return render_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
gbm_device* CHyprlock::createGBMDevice(drmDevice* dev) {
|
||||||
|
char* renderNode = gbm_find_render_node(dev);
|
||||||
|
|
||||||
|
if (!renderNode) {
|
||||||
|
Debug::log(ERR, "[core] Couldn't find a render node");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[core] createGBMDevice: render node {}", renderNode);
|
||||||
|
|
||||||
|
int fd = open(renderNode, O_RDWR | O_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
Debug::log(ERR, "[core] couldn't open render node");
|
||||||
|
free(renderNode);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(renderNode);
|
||||||
|
return gbm_create_device(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// end dmabuf
|
||||||
|
|
||||||
// wl_registry
|
// wl_registry
|
||||||
|
|
||||||
static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
|
static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
|
||||||
|
@ -75,11 +247,9 @@ void CHyprlock::onGlobal(void* data, struct wl_registry* registry, uint32_t name
|
||||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||||
} else if (IFACE == wl_output_interface.name) {
|
} else if (IFACE == wl_output_interface.name) {
|
||||||
m_vOutputs.emplace_back(std::make_unique<COutput>((wl_output*)wl_registry_bind(registry, name, &wl_output_interface, version), name));
|
m_vOutputs.emplace_back(std::make_unique<COutput>((wl_output*)wl_registry_bind(registry, name, &wl_output_interface, version), name));
|
||||||
|
|
||||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||||
} else if (IFACE == wp_cursor_shape_manager_v1_interface.name) {
|
} else if (IFACE == wp_cursor_shape_manager_v1_interface.name) {
|
||||||
m_pCursorShape = std::make_unique<CCursorShape>((wp_cursor_shape_manager_v1*)wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, version));
|
m_pCursorShape = std::make_unique<CCursorShape>((wp_cursor_shape_manager_v1*)wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, version));
|
||||||
|
|
||||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||||
} else if (IFACE == wl_compositor_interface.name) {
|
} else if (IFACE == wl_compositor_interface.name) {
|
||||||
m_sWaylandState.compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, version);
|
m_sWaylandState.compositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, version);
|
||||||
|
@ -90,6 +260,19 @@ void CHyprlock::onGlobal(void* data, struct wl_registry* registry, uint32_t name
|
||||||
} else if (IFACE == wp_viewporter_interface.name) {
|
} else if (IFACE == wp_viewporter_interface.name) {
|
||||||
m_sWaylandState.viewporter = (wp_viewporter*)wl_registry_bind(registry, name, &wp_viewporter_interface, version);
|
m_sWaylandState.viewporter = (wp_viewporter*)wl_registry_bind(registry, name, &wp_viewporter_interface, version);
|
||||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||||
|
} else if (IFACE == zwp_linux_dmabuf_v1_interface.name) {
|
||||||
|
if (version < 4) {
|
||||||
|
Debug::log(ERR, "cannot use linux_dmabuf with ver < 4");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma.linuxDmabuf = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version);
|
||||||
|
dma.linuxDmabufFeedback = zwp_linux_dmabuf_v1_get_default_feedback((zwp_linux_dmabuf_v1*)dma.linuxDmabuf);
|
||||||
|
zwp_linux_dmabuf_feedback_v1_add_listener((zwp_linux_dmabuf_feedback_v1*)dma.linuxDmabufFeedback, &dmabufFeedbackListener, nullptr);
|
||||||
|
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||||
|
} else if (IFACE == zwlr_screencopy_manager_v1_interface.name) {
|
||||||
|
m_sWaylandState.screencopy = (zwlr_screencopy_manager_v1*)wl_registry_bind(registry, name, &zwlr_screencopy_manager_v1_interface, version);
|
||||||
|
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +298,8 @@ void CHyprlock::run() {
|
||||||
// gather info about monitors
|
// gather info about monitors
|
||||||
wl_display_roundtrip(m_sWaylandState.display);
|
wl_display_roundtrip(m_sWaylandState.display);
|
||||||
|
|
||||||
|
g_pRenderer = std::make_unique<CRenderer>();
|
||||||
|
|
||||||
lockSession();
|
lockSession();
|
||||||
|
|
||||||
pollfd pollfds[] = {
|
pollfd pollfds[] = {
|
||||||
|
@ -244,8 +429,10 @@ void CHyprlock::run() {
|
||||||
m_sLoopState.timerEvent = true;
|
m_sLoopState.timerEvent = true;
|
||||||
m_sLoopState.timerCV.notify_all();
|
m_sLoopState.timerCV.notify_all();
|
||||||
g_pRenderer->asyncResourceGatherer->notify();
|
g_pRenderer->asyncResourceGatherer->notify();
|
||||||
|
g_pRenderer->asyncResourceGatherer->await();
|
||||||
|
|
||||||
m_vOutputs.clear();
|
m_vOutputs.clear();
|
||||||
|
g_pEGL.reset();
|
||||||
|
|
||||||
wl_display_disconnect(m_sWaylandState.display);
|
wl_display_disconnect(m_sWaylandState.display);
|
||||||
|
|
||||||
|
@ -491,8 +678,6 @@ void CHyprlock::unlockSession() {
|
||||||
ext_session_lock_v1_unlock_and_destroy(m_sLockState.lock);
|
ext_session_lock_v1_unlock_and_destroy(m_sLockState.lock);
|
||||||
m_sLockState.lock = nullptr;
|
m_sLockState.lock = nullptr;
|
||||||
|
|
||||||
m_vOutputs.clear();
|
|
||||||
g_pEGL.reset();
|
|
||||||
Debug::log(LOG, "Unlocked, exiting!");
|
Debug::log(LOG, "Unlocked, exiting!");
|
||||||
|
|
||||||
m_bTerminate = true;
|
m_bTerminate = true;
|
||||||
|
@ -619,3 +804,7 @@ std::string CHyprlock::spawnSync(const std::string& cmd) {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zwlr_screencopy_manager_v1* CHyprlock::getScreencopy() {
|
||||||
|
return m_sWaylandState.screencopy;
|
||||||
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include "ext-session-lock-v1-protocol.h"
|
#include "ext-session-lock-v1-protocol.h"
|
||||||
#include "fractional-scale-v1-protocol.h"
|
#include "fractional-scale-v1-protocol.h"
|
||||||
|
#include "linux-dmabuf-unstable-v1-protocol.h"
|
||||||
|
#include "wlr-screencopy-unstable-v1-protocol.h"
|
||||||
#include "viewporter-protocol.h"
|
#include "viewporter-protocol.h"
|
||||||
#include "Output.hpp"
|
#include "Output.hpp"
|
||||||
#include "CursorShape.hpp"
|
#include "CursorShape.hpp"
|
||||||
|
@ -16,6 +18,14 @@
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
|
||||||
|
#include <gbm.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
|
|
||||||
|
struct SDMABUFModifier {
|
||||||
|
uint32_t fourcc = 0;
|
||||||
|
uint64_t mod = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class CHyprlock {
|
class CHyprlock {
|
||||||
public:
|
public:
|
||||||
CHyprlock(const std::string& wlDisplay);
|
CHyprlock(const std::string& wlDisplay);
|
||||||
|
@ -49,6 +59,7 @@ class CHyprlock {
|
||||||
wl_display* getDisplay();
|
wl_display* getDisplay();
|
||||||
wp_fractional_scale_manager_v1* getFractionalMgr();
|
wp_fractional_scale_manager_v1* getFractionalMgr();
|
||||||
wp_viewporter* getViewporter();
|
wp_viewporter* getViewporter();
|
||||||
|
zwlr_screencopy_manager_v1* getScreencopy();
|
||||||
|
|
||||||
wl_pointer* m_pPointer = nullptr;
|
wl_pointer* m_pPointer = nullptr;
|
||||||
wl_keyboard* m_pKeeb = nullptr;
|
wl_keyboard* m_pKeeb = nullptr;
|
||||||
|
@ -65,6 +76,23 @@ class CHyprlock {
|
||||||
std::chrono::system_clock::time_point m_tGraceEnds;
|
std::chrono::system_clock::time_point m_tGraceEnds;
|
||||||
Vector2D m_vLastEnterCoords = {};
|
Vector2D m_vLastEnterCoords = {};
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<COutput>> m_vOutputs;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
void* linuxDmabuf = nullptr;
|
||||||
|
void* linuxDmabufFeedback = nullptr;
|
||||||
|
|
||||||
|
gbm_bo* gbm = nullptr;
|
||||||
|
gbm_device* gbmDevice = nullptr;
|
||||||
|
|
||||||
|
void* formatTable = nullptr;
|
||||||
|
size_t formatTableSize = 0;
|
||||||
|
bool deviceUsed = false;
|
||||||
|
|
||||||
|
std::vector<SDMABUFModifier> dmabufMods;
|
||||||
|
} dma;
|
||||||
|
gbm_device* createGBMDevice(drmDevice* dev);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct {
|
struct {
|
||||||
wl_display* display = nullptr;
|
wl_display* display = nullptr;
|
||||||
|
@ -74,6 +102,7 @@ class CHyprlock {
|
||||||
wl_compositor* compositor = nullptr;
|
wl_compositor* compositor = nullptr;
|
||||||
wp_fractional_scale_manager_v1* fractional = nullptr;
|
wp_fractional_scale_manager_v1* fractional = nullptr;
|
||||||
wp_viewporter* viewporter = nullptr;
|
wp_viewporter* viewporter = nullptr;
|
||||||
|
zwlr_screencopy_manager_v1* screencopy = nullptr;
|
||||||
} m_sWaylandState;
|
} m_sWaylandState;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -98,8 +127,6 @@ class CHyprlock {
|
||||||
bool timerEvent = false;
|
bool timerEvent = false;
|
||||||
} m_sLoopState;
|
} m_sLoopState;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<COutput>> m_vOutputs;
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CTimer>> m_vTimers;
|
std::vector<std::shared_ptr<CTimer>> m_vTimers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,42 @@ CAsyncResourceGatherer::CAsyncResourceGatherer() {
|
||||||
this->asyncLoopThread.detach();
|
this->asyncLoopThread.detach();
|
||||||
});
|
});
|
||||||
initThread.detach();
|
initThread.detach();
|
||||||
|
|
||||||
|
// some things can't be done async :(
|
||||||
|
// gather background textures when needed
|
||||||
|
|
||||||
|
const auto CWIDGETS = g_pConfigManager->getWidgetConfigs();
|
||||||
|
|
||||||
|
std::vector<std::string> mons;
|
||||||
|
|
||||||
|
for (auto& c : CWIDGETS) {
|
||||||
|
if (c.type != "background")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::string{std::any_cast<Hyprlang::STRING>(c.values.at("path"))} != "screenshot")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// mamma mia
|
||||||
|
if (c.monitor.empty()) {
|
||||||
|
mons.clear();
|
||||||
|
for (auto& m : g_pHyprlock->m_vOutputs) {
|
||||||
|
mons.push_back(m->stringPort);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
mons.push_back(c.monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& mon : mons) {
|
||||||
|
const auto MON = std::find_if(g_pHyprlock->m_vOutputs.begin(), g_pHyprlock->m_vOutputs.end(), [mon](const auto& other) { return other->stringPort == mon; });
|
||||||
|
|
||||||
|
if (MON == g_pHyprlock->m_vOutputs.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto PMONITOR = MON->get();
|
||||||
|
|
||||||
|
dmas.emplace_back(std::make_unique<CDMAFrame>(PMONITOR));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
||||||
|
@ -36,6 +72,11 @@ SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& dma : dmas) {
|
||||||
|
if (id == "dma:" + dma->name)
|
||||||
|
return dma->asset.ready ? &dma->asset : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +269,8 @@ void CAsyncResourceGatherer::asyncAssetSpinLock() {
|
||||||
|
|
||||||
asyncLoopState.busy = false;
|
asyncLoopState.busy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dmas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAsyncResourceGatherer::requestAsyncAssetPreload(const SPreloadRequest& request) {
|
void CAsyncResourceGatherer::requestAsyncAssetPreload(const SPreloadRequest& request) {
|
||||||
|
@ -247,3 +290,8 @@ void CAsyncResourceGatherer::notify() {
|
||||||
asyncLoopState.pending = true;
|
asyncLoopState.pending = true;
|
||||||
asyncLoopState.loopGuard.notify_all();
|
asyncLoopState.loopGuard.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CAsyncResourceGatherer::await() {
|
||||||
|
if (asyncLoopThread.joinable())
|
||||||
|
asyncLoopThread.join();
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Shader.hpp"
|
#include "Shader.hpp"
|
||||||
#include "../helpers/Box.hpp"
|
#include "../helpers/Box.hpp"
|
||||||
#include "../helpers/Color.hpp"
|
#include "../helpers/Color.hpp"
|
||||||
|
#include "DMAFrame.hpp"
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -10,10 +11,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <any>
|
#include <any>
|
||||||
|
#include "Shared.hpp"
|
||||||
struct SPreloadedAsset {
|
|
||||||
CTexture texture;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CAsyncResourceGatherer {
|
class CAsyncResourceGatherer {
|
||||||
public:
|
public:
|
||||||
|
@ -44,6 +42,7 @@ class CAsyncResourceGatherer {
|
||||||
void requestAsyncAssetPreload(const SPreloadRequest& request);
|
void requestAsyncAssetPreload(const SPreloadRequest& request);
|
||||||
void unloadAsset(SPreloadedAsset* asset);
|
void unloadAsset(SPreloadedAsset* asset);
|
||||||
void notify();
|
void notify();
|
||||||
|
void await();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread initThread;
|
std::thread initThread;
|
||||||
|
@ -77,6 +76,8 @@ class CAsyncResourceGatherer {
|
||||||
Vector2D size;
|
Vector2D size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<CDMAFrame>> dmas;
|
||||||
|
|
||||||
std::vector<SPreloadTarget> preloadTargets;
|
std::vector<SPreloadTarget> preloadTargets;
|
||||||
std::unordered_map<std::string, SPreloadedAsset> assets;
|
std::unordered_map<std::string, SPreloadedAsset> assets;
|
||||||
|
|
||||||
|
|
203
src/renderer/DMAFrame.cpp
Normal file
203
src/renderer/DMAFrame.cpp
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
#include "DMAFrame.hpp"
|
||||||
|
#include "wlr-screencopy-unstable-v1-protocol.h"
|
||||||
|
#include "../helpers/Log.hpp"
|
||||||
|
#include "../core/hyprlock.hpp"
|
||||||
|
#include "../core/Egl.hpp"
|
||||||
|
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
#include <GLES3/gl32.h>
|
||||||
|
#include <GLES3/gl3ext.h>
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
|
||||||
|
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
|
||||||
|
|
||||||
|
static void wlrOnBuffer(void* data, zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
|
||||||
|
const auto PDATA = (SScreencopyData*)data;
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[sc] wlrOnBuffer for {}", (void*)PDATA);
|
||||||
|
|
||||||
|
PDATA->size = stride * height;
|
||||||
|
PDATA->stride = stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wlrOnFlags(void* data, zwlr_screencopy_frame_v1* frame, uint32_t flags) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wlrOnReady(void* data, zwlr_screencopy_frame_v1* frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||||
|
const auto PDATA = (SScreencopyData*)data;
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[sc] wlrOnReady for {}", (void*)PDATA);
|
||||||
|
|
||||||
|
if (!PDATA->frame->onBufferReady()) {
|
||||||
|
Debug::log(ERR, "onBufferReady failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
zwlr_screencopy_frame_v1_destroy(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wlrOnFailed(void* data, zwlr_screencopy_frame_v1* frame) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wlrOnDamage(void* data, zwlr_screencopy_frame_v1* frame, uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wlrOnDmabuf(void* data, zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height) {
|
||||||
|
const auto PDATA = (SScreencopyData*)data;
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[sc] wlrOnDmabuf for {}", (void*)PDATA);
|
||||||
|
|
||||||
|
PDATA->w = width;
|
||||||
|
PDATA->h = height;
|
||||||
|
PDATA->fmt = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wlrOnBufferDone(void* data, zwlr_screencopy_frame_v1* frame) {
|
||||||
|
const auto PDATA = (SScreencopyData*)data;
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[sc] wlrOnBufferDone for {}", (void*)PDATA);
|
||||||
|
|
||||||
|
if (!PDATA->frame->onBufferDone()) {
|
||||||
|
Debug::log(ERR, "onBufferDone failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
zwlr_screencopy_frame_v1_copy(frame, PDATA->frame->wlBuffer);
|
||||||
|
|
||||||
|
Debug::log(TRACE, "[sc] wlr frame copied");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const zwlr_screencopy_frame_v1_listener wlrFrameListener = {
|
||||||
|
.buffer = wlrOnBuffer,
|
||||||
|
.flags = wlrOnFlags,
|
||||||
|
.ready = wlrOnReady,
|
||||||
|
.failed = wlrOnFailed,
|
||||||
|
.damage = wlrOnDamage,
|
||||||
|
.linux_dmabuf = wlrOnDmabuf,
|
||||||
|
.buffer_done = wlrOnBufferDone,
|
||||||
|
};
|
||||||
|
|
||||||
|
CDMAFrame::CDMAFrame(COutput* output) {
|
||||||
|
|
||||||
|
if (!glEGLImageTargetTexture2DOES) {
|
||||||
|
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||||
|
if (!glEGLImageTargetTexture2DOES) {
|
||||||
|
Debug::log(ERR, "No glEGLImageTargetTexture2DOES??");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstly, plant a listener for the frame
|
||||||
|
frameCb = zwlr_screencopy_manager_v1_capture_output(g_pHyprlock->getScreencopy(), false, output->output);
|
||||||
|
|
||||||
|
scdata.frame = this;
|
||||||
|
|
||||||
|
zwlr_screencopy_frame_v1_add_listener(frameCb, &wlrFrameListener, &scdata);
|
||||||
|
|
||||||
|
name = output->stringPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMAFrame::~CDMAFrame() {
|
||||||
|
if (g_pEGL)
|
||||||
|
eglDestroyImage(g_pEGL->eglDisplay, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMAFrame::onBufferDone() {
|
||||||
|
uint32_t flags = GBM_BO_USE_RENDERING;
|
||||||
|
|
||||||
|
bo = gbm_bo_create(g_pHyprlock->dma.gbmDevice, scdata.w, scdata.h, scdata.fmt, flags);
|
||||||
|
|
||||||
|
if (!bo) {
|
||||||
|
Debug::log(ERR, "Couldn't create a drm buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
planes = gbm_bo_get_plane_count(bo);
|
||||||
|
|
||||||
|
zwp_linux_buffer_params_v1* params = zwp_linux_dmabuf_v1_create_params((zwp_linux_dmabuf_v1*)g_pHyprlock->dma.linuxDmabuf);
|
||||||
|
if (!params) {
|
||||||
|
Debug::log(ERR, "zwp_linux_dmabuf_v1_create_params failed");
|
||||||
|
gbm_bo_destroy(bo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t plane = 0; plane < (size_t)planes; plane++) {
|
||||||
|
size[plane] = 0;
|
||||||
|
stride[plane] = gbm_bo_get_stride_for_plane(bo, plane);
|
||||||
|
offset[plane] = gbm_bo_get_offset(bo, plane);
|
||||||
|
uint64_t mod = gbm_bo_get_modifier(bo);
|
||||||
|
fd[plane] = gbm_bo_get_fd_for_plane(bo, plane);
|
||||||
|
|
||||||
|
if (fd[plane] < 0) {
|
||||||
|
Debug::log(ERR, "gbm_bo_get_fd_for_plane failed");
|
||||||
|
zwp_linux_buffer_params_v1_destroy(params);
|
||||||
|
gbm_bo_destroy(bo);
|
||||||
|
for (size_t plane_tmp = 0; plane_tmp < plane; plane_tmp++) {
|
||||||
|
close(fd[plane_tmp]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
zwp_linux_buffer_params_v1_add(params, fd[plane], plane, offset[plane], stride[plane], mod >> 32, mod & 0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlBuffer = zwp_linux_buffer_params_v1_create_immed(params, scdata.w, scdata.h, scdata.fmt, 0);
|
||||||
|
zwp_linux_buffer_params_v1_destroy(params);
|
||||||
|
|
||||||
|
if (!wlBuffer) {
|
||||||
|
Debug::log(ERR, "[pw] zwp_linux_buffer_params_v1_create_immed failed");
|
||||||
|
gbm_bo_destroy(bo);
|
||||||
|
for (size_t plane = 0; plane < (size_t)planes; plane++)
|
||||||
|
close(fd[plane]);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMAFrame::onBufferReady() {
|
||||||
|
static const int general_attribs = 3;
|
||||||
|
static const int plane_attribs = 5;
|
||||||
|
static const int entries_per_attrib = 2;
|
||||||
|
EGLAttrib attribs[(general_attribs + plane_attribs * 4) * entries_per_attrib + 1];
|
||||||
|
int attr = 0;
|
||||||
|
attribs[attr++] = EGL_WIDTH;
|
||||||
|
attribs[attr++] = scdata.w;
|
||||||
|
attribs[attr++] = EGL_HEIGHT;
|
||||||
|
attribs[attr++] = scdata.h;
|
||||||
|
attribs[attr++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||||
|
attribs[attr++] = scdata.fmt;
|
||||||
|
attribs[attr++] = EGL_DMA_BUF_PLANE0_FD_EXT;
|
||||||
|
attribs[attr++] = fd[0];
|
||||||
|
attribs[attr++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
|
||||||
|
attribs[attr++] = offset[0];
|
||||||
|
attribs[attr++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
|
||||||
|
attribs[attr++] = stride[0];
|
||||||
|
attribs[attr] = EGL_NONE;
|
||||||
|
|
||||||
|
image = eglCreateImage(g_pEGL->eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
|
||||||
|
|
||||||
|
if (image == EGL_NO_IMAGE) {
|
||||||
|
Debug::log(ERR, "failed creating an egl image");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset.texture.allocate();
|
||||||
|
asset.texture.m_vSize = {scdata.w, scdata.h};
|
||||||
|
glBindTexture(GL_TEXTURE_2D, asset.texture.m_iTexID);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
asset.ready = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
46
src/renderer/DMAFrame.hpp
Normal file
46
src/renderer/DMAFrame.hpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../core/Output.hpp"
|
||||||
|
#include <gbm.h>
|
||||||
|
#include "Texture.hpp"
|
||||||
|
#include "Shared.hpp"
|
||||||
|
|
||||||
|
struct zwlr_screencopy_frame_v1;
|
||||||
|
|
||||||
|
class CDMAFrame;
|
||||||
|
|
||||||
|
struct SScreencopyData {
|
||||||
|
int w = 0, h = 0;
|
||||||
|
uint32_t fmt;
|
||||||
|
size_t size;
|
||||||
|
size_t stride;
|
||||||
|
CDMAFrame* frame = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDMAFrame {
|
||||||
|
public:
|
||||||
|
CDMAFrame(COutput* mon);
|
||||||
|
~CDMAFrame();
|
||||||
|
|
||||||
|
bool onBufferDone();
|
||||||
|
bool onBufferReady();
|
||||||
|
|
||||||
|
wl_buffer* wlBuffer = nullptr;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
SPreloadedAsset asset;
|
||||||
|
|
||||||
|
private:
|
||||||
|
gbm_bo* bo = nullptr;
|
||||||
|
|
||||||
|
int planes = 0;
|
||||||
|
|
||||||
|
int fd[4];
|
||||||
|
uint32_t size[4], stride[4], offset[4];
|
||||||
|
|
||||||
|
zwlr_screencopy_frame_v1* frameCb = nullptr;
|
||||||
|
SScreencopyData scdata;
|
||||||
|
|
||||||
|
EGLImage image = nullptr;
|
||||||
|
};
|
|
@ -255,8 +255,14 @@ std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CS
|
||||||
// by type
|
// by type
|
||||||
if (c.type == "background") {
|
if (c.type == "background") {
|
||||||
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
||||||
widgets[surf].emplace_back(
|
|
||||||
std::make_unique<CBackground>(surf->size, PATH.empty() ? "" : std::string{"background:"} + PATH, std::any_cast<Hyprlang::INT>(c.values.at("color"))));
|
std::string resourceID = "";
|
||||||
|
if (PATH == "screenshot")
|
||||||
|
resourceID = "dma:" + surf->output->stringPort;
|
||||||
|
else if (!PATH.empty())
|
||||||
|
resourceID = "background:" + PATH;
|
||||||
|
|
||||||
|
widgets[surf].emplace_back(std::make_unique<CBackground>(surf->size, resourceID, std::any_cast<Hyprlang::INT>(c.values.at("color"))));
|
||||||
} else if (c.type == "input-field") {
|
} else if (c.type == "input-field") {
|
||||||
widgets[surf].emplace_back(std::make_unique<CPasswordInputField>(surf->size, c.values));
|
widgets[surf].emplace_back(std::make_unique<CPasswordInputField>(surf->size, c.values));
|
||||||
} else if (c.type == "label") {
|
} else if (c.type == "label") {
|
||||||
|
|
7
src/renderer/Shared.hpp
Normal file
7
src/renderer/Shared.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Texture.hpp"
|
||||||
|
|
||||||
|
struct SPreloadedAsset {
|
||||||
|
CTexture texture;
|
||||||
|
bool ready = false;
|
||||||
|
};
|
Loading…
Reference in a new issue