mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-23 02:05:58 +01:00
core/surface/buffer: Buffer lock/release fixes (#7110)
This commit is contained in:
parent
5489682799
commit
37e1411e8d
27 changed files with 304 additions and 129 deletions
|
@ -242,7 +242,7 @@ void CLayerSurface::onCommit() {
|
||||||
|
|
||||||
if (!mapped) {
|
if (!mapped) {
|
||||||
// we're re-mapping if this is the case
|
// we're re-mapping if this is the case
|
||||||
if (layerSurface->surface && !layerSurface->surface->current.buffer) {
|
if (layerSurface->surface && !layerSurface->surface->current.texture) {
|
||||||
fadingOut = false;
|
fadingOut = false;
|
||||||
geometry = {};
|
geometry = {};
|
||||||
g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
|
g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
|
||||||
|
|
|
@ -57,12 +57,12 @@ bool CWLSurface::small() const {
|
||||||
if (!validMapped(m_pWindowOwner) || !exists())
|
if (!validMapped(m_pWindowOwner) || !exists())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_pResource->current.buffer)
|
if (!m_pResource->current.texture)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto O = m_pWindowOwner.lock();
|
const auto O = m_pWindowOwner.lock();
|
||||||
|
|
||||||
return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->size.y + 1;
|
return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D CWLSurface::correctSmallVec() const {
|
Vector2D CWLSurface::correctSmallVec() const {
|
||||||
|
@ -76,37 +76,36 @@ Vector2D CWLSurface::correctSmallVec() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D CWLSurface::correctSmallVecBuf() const {
|
Vector2D CWLSurface::correctSmallVecBuf() const {
|
||||||
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.buffer)
|
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const auto SIZE = getViewporterCorrectedSize();
|
const auto SIZE = getViewporterCorrectedSize();
|
||||||
const auto BS = m_pResource->current.buffer->size;
|
const auto BS = m_pResource->current.bufferSize;
|
||||||
|
|
||||||
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
|
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D CWLSurface::getViewporterCorrectedSize() const {
|
Vector2D CWLSurface::getViewporterCorrectedSize() const {
|
||||||
if (!exists() || !m_pResource->current.buffer)
|
if (!exists() || !m_pResource->current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size;
|
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
CRegion CWLSurface::computeDamage() const {
|
CRegion CWLSurface::computeDamage() const {
|
||||||
if (!m_pResource->current.buffer)
|
if (!m_pResource->current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
CRegion damage = m_pResource->accumulateCurrentBufferDamage();
|
CRegion damage = m_pResource->accumulateCurrentBufferDamage();
|
||||||
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y);
|
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
|
||||||
|
|
||||||
const auto BUFSIZE = m_pResource->current.buffer->size;
|
const auto BUFSIZE = m_pResource->current.bufferSize;
|
||||||
const auto CORRECTVEC = correctSmallVecBuf();
|
const auto CORRECTVEC = correctSmallVecBuf();
|
||||||
|
|
||||||
if (m_pResource->current.viewport.hasSource)
|
if (m_pResource->current.viewport.hasSource)
|
||||||
damage.intersect(m_pResource->current.viewport.source);
|
damage.intersect(m_pResource->current.viewport.source);
|
||||||
|
|
||||||
const auto SCALEDSRCSIZE =
|
const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize;
|
||||||
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size;
|
|
||||||
|
|
||||||
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
|
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
|
||||||
damage.translate(CORRECTVEC);
|
damage.translate(CORRECTVEC);
|
||||||
|
@ -114,7 +113,7 @@ CRegion CWLSurface::computeDamage() const {
|
||||||
// go from buffer coords in the damage to hl logical
|
// go from buffer coords in the damage to hl logical
|
||||||
|
|
||||||
const auto BOX = getSurfaceBoxGlobal();
|
const auto BOX = getSurfaceBoxGlobal();
|
||||||
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.buffer->size :
|
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.bufferSize :
|
||||||
Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */};
|
Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */};
|
||||||
|
|
||||||
damage.scale(SCALE);
|
damage.scale(SCALE);
|
||||||
|
|
|
@ -1097,18 +1097,18 @@ bool CWindow::opaque() {
|
||||||
if (PWORKSPACE->m_fAlpha.value() != 1.f)
|
if (PWORKSPACE->m_fAlpha.value() != 1.f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer)
|
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture)
|
||||||
return m_pXWaylandSurface->surface->current.buffer->opaque;
|
return m_pXWaylandSurface->surface->current.texture->m_bOpaque;
|
||||||
|
|
||||||
if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer)
|
if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.texture)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: this is wrong
|
// TODO: this is wrong
|
||||||
const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents();
|
const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents();
|
||||||
if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y)
|
if (EXTENTS.w >= m_pXDGSurface->surface->current.bufferSize.x && EXTENTS.h >= m_pXDGSurface->surface->current.bufferSize.y)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return m_pWLSurface->resource()->current.buffer->opaque;
|
return m_pWLSurface->resource()->current.texture->m_bOpaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
float CWindow::rounding() {
|
float CWindow::rounding() {
|
||||||
|
|
|
@ -752,7 +752,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||||
|
|
||||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||||
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) {
|
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
|
||||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
||||||
|
|
||||||
if (!damageBox.empty()) {
|
if (!damageBox.empty()) {
|
||||||
|
|
|
@ -801,17 +801,16 @@ bool CMonitor::attemptDirectScanout() {
|
||||||
|
|
||||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||||
|
|
||||||
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform)
|
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we can't scanout shm buffers.
|
// we can't scanout shm buffers.
|
||||||
if (!PSURFACE->current.buffer->dmabuf().success)
|
if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
|
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
|
||||||
// and comes from the appropriate device. This may implode on multi-gpu!!
|
// and comes from the appropriate device. This may implode on multi-gpu!!
|
||||||
|
output->state->setBuffer(PSURFACE->current.buffer->buffer.lock());
|
||||||
output->state->setBuffer(PSURFACE->current.buffer);
|
|
||||||
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
|
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
|
||||||
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../protocols/PointerGestures.hpp"
|
#include "../protocols/PointerGestures.hpp"
|
||||||
#include "../protocols/FractionalScale.hpp"
|
#include "../protocols/FractionalScale.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
#include "../protocols/core/Seat.hpp"
|
||||||
#include "eventLoop/EventLoopManager.hpp"
|
#include "eventLoop/EventLoopManager.hpp"
|
||||||
#include "SeatManager.hpp"
|
#include "SeatManager.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -156,15 +157,15 @@ void CPointerManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hots
|
||||||
currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); });
|
currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); });
|
||||||
currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) {
|
currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) {
|
||||||
damageIfSoftware();
|
damageIfSoftware();
|
||||||
currentCursorImage.size = currentCursorImage.surface->resource()->current.buffer ? currentCursorImage.surface->resource()->current.buffer->size : Vector2D{};
|
currentCursorImage.size = currentCursorImage.surface->resource()->current.texture ? currentCursorImage.surface->resource()->current.bufferSize : Vector2D{};
|
||||||
currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F;
|
currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F;
|
||||||
recheckEnteredOutputs();
|
recheckEnteredOutputs();
|
||||||
updateCursorBackend();
|
updateCursorBackend();
|
||||||
damageIfSoftware();
|
damageIfSoftware();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (surf->resource()->current.buffer) {
|
if (surf->resource()->current.texture) {
|
||||||
currentCursorImage.size = surf->resource()->current.buffer->size;
|
currentCursorImage.size = surf->resource()->current.bufferSize;
|
||||||
timespec now;
|
timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
surf->resource()->frame(&now);
|
surf->resource()->frame(&now);
|
||||||
|
@ -430,16 +431,39 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
|
||||||
// clear buffer
|
// clear buffer
|
||||||
memset(bufPtr, 0, std::get<2>(bufData));
|
memset(bufPtr, 0, std::get<2>(bufData));
|
||||||
|
|
||||||
auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer;
|
if (currentCursorImage.pBuffer) {
|
||||||
|
auto texAttrs = currentCursorImage.pBuffer->shm();
|
||||||
|
|
||||||
if (texBuffer) {
|
if (!texAttrs.success) {
|
||||||
auto textAttrs = texBuffer->shm();
|
Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers");
|
||||||
auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE);
|
return nullptr;
|
||||||
auto texPtr = std::get<0>(texData);
|
}
|
||||||
Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride);
|
|
||||||
|
auto texData = currentCursorImage.pBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE);
|
||||||
|
auto texPtr = std::get<0>(texData);
|
||||||
|
Debug::log(TRACE, "cursor texture {}x{} {} {} {}", texAttrs.size.x, texAttrs.size.y, (void*)texPtr, texAttrs.format, texAttrs.stride);
|
||||||
// copy cursor texture
|
// copy cursor texture
|
||||||
for (int i = 0; i < texBuffer->shm().size.y; i++)
|
for (int i = 0; i < texAttrs.size.y; i++)
|
||||||
memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride);
|
memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * texAttrs.stride, texAttrs.stride);
|
||||||
|
} else if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) {
|
||||||
|
const auto SURFACE = currentCursorImage.surface->resource();
|
||||||
|
auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE);
|
||||||
|
Debug::log(TRACE, "cursor texture pixel data length: {}B", shmBuffer.size());
|
||||||
|
|
||||||
|
if (shmBuffer.data()) {
|
||||||
|
// copy cursor texture
|
||||||
|
// assume format is 32bpp
|
||||||
|
size_t STRIDE = 4 * SURFACE->current.bufferSize.x;
|
||||||
|
for (int i = 0; i < SURFACE->current.bufferSize.y; i++)
|
||||||
|
memcpy(bufPtr + i * buf->dmabuf().strides[0], shmBuffer.data() + i * STRIDE, STRIDE);
|
||||||
|
} else {
|
||||||
|
// if there is no data, hide the cursor
|
||||||
|
memset(bufPtr, '\0', buf->size.x * buf->size.y * 4 /* assume 32bpp */);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Debug::log(TRACE, "Unsupported cursor buffer/surface, falling back to sw (can't dumb copy)");
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->endDataPtr();
|
buf->endDataPtr();
|
||||||
|
@ -740,7 +764,7 @@ void CPointerManager::onMonitorLayoutChange() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CTexture> CPointerManager::getCurrentCursorTexture() {
|
SP<CTexture> CPointerManager::getCurrentCursorTexture() {
|
||||||
if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.buffer))
|
if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.texture))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (currentCursorImage.pBuffer) {
|
if (currentCursorImage.pBuffer) {
|
||||||
|
@ -749,7 +773,7 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
|
||||||
return currentCursorImage.bufferTex;
|
return currentCursorImage.bufferTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentCursorImage.surface->resource()->current.buffer->texture;
|
return currentCursorImage.surface->resource()->current.texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) {
|
if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) {
|
||||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
|
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
|
||||||
surface->pending.rejected = true;
|
surface->pending.rejected = true;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -107,14 +107,14 @@ CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_,
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
||||||
if (pSurface->current.buffer && !mapped) {
|
if (pSurface->current.texture && !mapped) {
|
||||||
mapped = true;
|
mapped = true;
|
||||||
pSurface->map();
|
pSurface->map();
|
||||||
events.map.emit();
|
events.map.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pSurface->current.buffer && mapped) {
|
if (!pSurface->current.texture && mapped) {
|
||||||
mapped = false;
|
mapped = false;
|
||||||
pSurface->unmap();
|
pSurface->unmap();
|
||||||
events.unmap.emit();
|
events.unmap.emit();
|
||||||
|
|
|
@ -44,7 +44,7 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<C
|
||||||
current = pending;
|
current = pending;
|
||||||
pending.committed = 0;
|
pending.committed = 0;
|
||||||
|
|
||||||
bool attachedBuffer = surface->current.buffer;
|
bool attachedBuffer = surface->current.texture;
|
||||||
|
|
||||||
if (attachedBuffer && !configured) {
|
if (attachedBuffer && !configured) {
|
||||||
surface->error(-1, "layerSurface was not configured, but a buffer was attached");
|
surface->error(-1, "layerSurface was not configured, but a buffer was attached");
|
||||||
|
|
|
@ -24,7 +24,7 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_,
|
||||||
resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; });
|
resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; });
|
||||||
|
|
||||||
listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) {
|
listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) {
|
||||||
if (!pSurface->current.buffer) {
|
if (!pSurface->current.texture) {
|
||||||
LOGM(ERR, "SessionLock attached a null buffer");
|
LOGM(ERR, "SessionLock attached a null buffer");
|
||||||
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
|
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -54,13 +54,13 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
||||||
if (!surface || !surface->pending.buffer)
|
if (!surface || !surface->pending.texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface->pending.viewport.hasSource) {
|
if (surface->pending.viewport.hasSource) {
|
||||||
auto& src = surface->pending.viewport.source;
|
auto& src = surface->pending.viewport.source;
|
||||||
|
|
||||||
if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) {
|
if (src.w + src.x > surface->pending.bufferSize.x || src.h + src.y > surface->pending.bufferSize.y) {
|
||||||
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
||||||
surface->pending.rejected = true;
|
surface->pending.rejected = true;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -347,12 +347,12 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
||||||
if (toplevel)
|
if (toplevel)
|
||||||
toplevel->current = toplevel->pending;
|
toplevel->current = toplevel->pending;
|
||||||
|
|
||||||
if (initialCommit && surface->pending.buffer) {
|
if (initialCommit && surface->pending.texture) {
|
||||||
resource->error(-1, "Buffer attached before initial commit");
|
resource->error(-1, "Buffer attached before initial commit");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->current.buffer && !mapped) {
|
if (surface->current.texture && !mapped) {
|
||||||
// this forces apps to not draw CSD.
|
// this forces apps to not draw CSD.
|
||||||
if (toplevel)
|
if (toplevel)
|
||||||
toplevel->setMaximized(true);
|
toplevel->setMaximized(true);
|
||||||
|
@ -363,7 +363,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->current.buffer && mapped) {
|
if (!surface->current.texture && mapped) {
|
||||||
mapped = false;
|
mapped = false;
|
||||||
events.unmap.emit();
|
events.unmap.emit();
|
||||||
surface->unmap();
|
surface->unmap();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Compositor.hpp"
|
#include "Compositor.hpp"
|
||||||
#include "Output.hpp"
|
#include "Output.hpp"
|
||||||
|
#include "Seat.hpp"
|
||||||
#include "../types/WLBuffer.hpp"
|
#include "../types/WLBuffer.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
#include "../PresentationTime.hpp"
|
#include "../PresentationTime.hpp"
|
||||||
#include "../DRMSyncobj.hpp"
|
#include "../DRMSyncobj.hpp"
|
||||||
#include "../../render/Renderer.hpp"
|
#include "../../render/Renderer.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#define LOGM PROTO::compositor->protoLog
|
#define LOGM PROTO::compositor->protoLog
|
||||||
|
|
||||||
|
@ -19,8 +21,6 @@ class CDefaultSurfaceRole : public ISurfaceRole {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SP<CDefaultSurfaceRole> defaultRole = makeShared<CDefaultSurfaceRole>();
|
|
||||||
|
|
||||||
CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) {
|
CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||||
|
|
||||||
resource->setData(this);
|
resource->setData(this);
|
||||||
|
|
||||||
role = defaultRole;
|
role = makeShared<CDefaultSurfaceRole>();
|
||||||
|
|
||||||
resource->setDestroy([this](CWlSurface* r) { destroy(); });
|
resource->setDestroy([this](CWlSurface* r) { destroy(); });
|
||||||
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
|
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
|
||||||
|
@ -75,41 +75,42 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||||
pending.buffer.reset();
|
pending.buffer.reset();
|
||||||
pending.texture.reset();
|
pending.texture.reset();
|
||||||
} else {
|
} else {
|
||||||
auto res = CWLBufferResource::fromResource(buffer);
|
auto res = CWLBufferResource::fromResource(buffer);
|
||||||
pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr;
|
pending.buffer = res && res->buffer ? makeShared<CHLBufferReference>(res->buffer.lock(), self.lock()) : nullptr;
|
||||||
pending.size = res && res->buffer ? res->buffer->size : Vector2D{};
|
pending.size = res && res->buffer ? res->buffer->size : Vector2D{};
|
||||||
pending.texture = res && res->buffer ? res->buffer->texture : nullptr;
|
pending.texture = res && res->buffer ? res->buffer->texture : nullptr;
|
||||||
if (res)
|
pending.bufferSize = res && res->buffer ? res->buffer->size : Vector2D{};
|
||||||
res->released = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{};
|
Vector2D oldBufSize = current.buffer ? current.bufferSize : Vector2D{};
|
||||||
Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{};
|
Vector2D newBufSize = pending.buffer ? pending.bufferSize : Vector2D{};
|
||||||
|
|
||||||
if (oldBufSize != newBufSize || current.buffer != pending.buffer)
|
if (oldBufSize != newBufSize || current.buffer != pending.buffer)
|
||||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setCommit([this](CWlSurface* r) {
|
resource->setCommit([this](CWlSurface* r) {
|
||||||
if (pending.buffer)
|
if (pending.texture)
|
||||||
pending.bufferDamage.intersect(CBox{{}, pending.buffer->size});
|
pending.bufferDamage.intersect(CBox{{}, pending.bufferSize});
|
||||||
|
|
||||||
if (!pending.buffer)
|
if (!pending.texture)
|
||||||
pending.size = {};
|
pending.size = {};
|
||||||
else if (pending.viewport.hasDestination)
|
else if (pending.viewport.hasDestination)
|
||||||
pending.size = pending.viewport.destination;
|
pending.size = pending.viewport.destination;
|
||||||
else if (pending.viewport.hasSource)
|
else if (pending.viewport.hasSource)
|
||||||
pending.size = pending.viewport.source.size();
|
pending.size = pending.viewport.source.size();
|
||||||
else {
|
else {
|
||||||
Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size;
|
Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.bufferSize.y, pending.bufferSize.x} : pending.bufferSize;
|
||||||
pending.size = tfs / pending.scale;
|
pending.size = tfs / pending.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
pending.damage.intersect(CBox{{}, pending.size});
|
pending.damage.intersect(CBox{{}, pending.size});
|
||||||
|
|
||||||
events.precommit.emit();
|
events.precommit.emit();
|
||||||
if (pending.rejected)
|
if (pending.rejected) {
|
||||||
|
dropPendingBuffer();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (stateLocks <= 0)
|
if (stateLocks <= 0)
|
||||||
commitPendingState();
|
commitPendingState();
|
||||||
|
@ -160,6 +161,14 @@ void CWLSurfaceResource::destroy() {
|
||||||
PROTO::compositor->destroyResource(this);
|
PROTO::compositor->destroyResource(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::dropPendingBuffer() {
|
||||||
|
pending.buffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::dropCurrentBuffer() {
|
||||||
|
current.buffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
|
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
|
||||||
auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data());
|
auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data());
|
||||||
return data ? data->self.lock() : nullptr;
|
return data ? data->self.lock() : nullptr;
|
||||||
|
@ -240,7 +249,7 @@ void CWLSurfaceResource::frame(timespec* now) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::resetRole() {
|
void CWLSurfaceResource::resetRole() {
|
||||||
role = defaultRole;
|
role = makeShared<CDefaultSurfaceRole>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
|
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
|
||||||
|
@ -254,6 +263,8 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std
|
||||||
for (auto& c : n->subsurfaces) {
|
for (auto& c : n->subsurfaces) {
|
||||||
if (c->zIndex >= 0)
|
if (c->zIndex >= 0)
|
||||||
break;
|
break;
|
||||||
|
if (c->surface.expired())
|
||||||
|
continue;
|
||||||
nodes2.push_back(c->surface.lock());
|
nodes2.push_back(c->surface.lock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,6 +288,8 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std
|
||||||
for (auto& c : n->subsurfaces) {
|
for (auto& c : n->subsurfaces) {
|
||||||
if (c->zIndex < 0)
|
if (c->zIndex < 0)
|
||||||
continue;
|
continue;
|
||||||
|
if (c->surface.expired())
|
||||||
|
continue;
|
||||||
nodes2.push_back(c->surface.lock());
|
nodes2.push_back(c->surface.lock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,14 +356,9 @@ void CWLSurfaceResource::unmap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::releaseBuffers(bool onlyCurrent) {
|
void CWLSurfaceResource::releaseBuffers(bool onlyCurrent) {
|
||||||
if (current.buffer && !current.buffer->resource->released)
|
|
||||||
current.buffer->sendRelease();
|
|
||||||
if (pending.buffer && !pending.buffer->resource->released && !onlyCurrent)
|
|
||||||
pending.buffer->sendRelease();
|
|
||||||
|
|
||||||
pending.buffer.reset();
|
|
||||||
if (!onlyCurrent)
|
if (!onlyCurrent)
|
||||||
current.buffer.reset();
|
dropPendingBuffer();
|
||||||
|
dropCurrentBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::error(int code, const std::string& str) {
|
void CWLSurfaceResource::error(int code, const std::string& str) {
|
||||||
|
@ -375,18 +383,18 @@ CBox CWLSurfaceResource::extends() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D CWLSurfaceResource::sourceSize() {
|
Vector2D CWLSurfaceResource::sourceSize() {
|
||||||
if (!current.buffer)
|
if (!current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (current.viewport.hasSource)
|
if (current.viewport.hasSource)
|
||||||
return current.viewport.source.size();
|
return current.viewport.source.size();
|
||||||
|
|
||||||
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
|
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
|
||||||
return trc / current.scale;
|
return trc / current.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
||||||
if (!current.buffer)
|
if (!current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
CRegion surfaceDamage = current.damage;
|
CRegion surfaceDamage = current.damage;
|
||||||
|
@ -398,7 +406,7 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
||||||
if (current.viewport.hasSource)
|
if (current.viewport.hasSource)
|
||||||
surfaceDamage.translate(current.viewport.source.pos());
|
surfaceDamage.translate(current.viewport.source.pos());
|
||||||
|
|
||||||
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
|
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
|
||||||
|
|
||||||
return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
|
return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
|
||||||
}
|
}
|
||||||
|
@ -421,16 +429,21 @@ void CWLSurfaceResource::commitPendingState() {
|
||||||
pending.damage.clear();
|
pending.damage.clear();
|
||||||
pending.bufferDamage.clear();
|
pending.bufferDamage.clear();
|
||||||
|
|
||||||
if (current.buffer && current.buffer->texture)
|
if (current.texture)
|
||||||
current.buffer->texture->m_eTransform = wlTransformToHyprutils(current.transform);
|
current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
|
||||||
|
|
||||||
if (current.buffer && !current.buffer->resource->released) {
|
if (current.buffer && current.buffer->buffer) {
|
||||||
current.buffer->update(accumulateCurrentBufferDamage());
|
current.buffer->buffer->update(accumulateCurrentBufferDamage());
|
||||||
|
|
||||||
|
// if the surface is a cursor, update the shm buffer
|
||||||
|
// TODO: don't update the entire texture
|
||||||
|
if (role->role() == SURFACE_ROLE_CURSOR)
|
||||||
|
updateCursorShm();
|
||||||
|
|
||||||
// release the buffer if it's synchronous as update() has done everything thats needed
|
// release the buffer if it's synchronous as update() has done everything thats needed
|
||||||
// so we can let the app know we're done.
|
// so we can let the app know we're done.
|
||||||
if (current.buffer->isSynchronous())
|
if (current.buffer->buffer->isSynchronous())
|
||||||
current.buffer->sendReleaseWithSurface(self.lock());
|
dropCurrentBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we should _accumulate_ and not replace above if sync
|
// TODO: we should _accumulate_ and not replace above if sync
|
||||||
|
@ -455,20 +468,37 @@ void CWLSurfaceResource::commitPendingState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// for async buffers, we can only release the buffer once we are unrefing it from current.
|
// for async buffers, we can only release the buffer once we are unrefing it from current.
|
||||||
if (previousBuffer && !previousBuffer->isSynchronous() && !previousBuffer->resource->released) {
|
// if the backend took it, ref it with the lambda. Otherwise, the end of this scope will release it.
|
||||||
if (previousBuffer->lockedByBackend) {
|
if (previousBuffer && previousBuffer->buffer && !previousBuffer->buffer->isSynchronous()) {
|
||||||
previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) {
|
if (previousBuffer->buffer->lockedByBackend && !previousBuffer->buffer->hlEvents.backendRelease) {
|
||||||
if (!self.expired()) // could be dead in the dtor
|
previousBuffer->buffer->lock();
|
||||||
previousBuffer->sendReleaseWithSurface(self.lock());
|
previousBuffer->buffer->unlockOnBufferRelease(self);
|
||||||
else
|
}
|
||||||
previousBuffer->sendRelease();
|
|
||||||
previousBuffer->hlEvents.backendRelease.reset();
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
previousBuffer->sendReleaseWithSurface(self.lock());
|
|
||||||
|
|
||||||
previousBuffer->resource->released = true; // set it here regardless so we dont set more listeners for backendRelease
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastBuffer = current.buffer ? current.buffer->buffer : WP<IHLBuffer>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::updateCursorShm() {
|
||||||
|
auto buf = current.buffer ? current.buffer : lastBuffer;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: actually use damage
|
||||||
|
auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock());
|
||||||
|
auto shmAttrs = current.buffer->buffer->shm();
|
||||||
|
|
||||||
|
if (!shmAttrs.success) {
|
||||||
|
LOGM(TRACE, "updateCursorShm: ignoring, not a shm buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to end, shm.
|
||||||
|
auto [pixelData, fmt, bufLen] = current.buffer->buffer->beginDataPtr(0);
|
||||||
|
|
||||||
|
shmData.resize(bufLen);
|
||||||
|
memcpy(shmData.data(), pixelData, bufLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) {
|
void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) {
|
||||||
|
|
|
@ -84,13 +84,13 @@ class CWLSurfaceResource {
|
||||||
} events;
|
} events;
|
||||||
|
|
||||||
struct SState {
|
struct SState {
|
||||||
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
||||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
int scale = 1;
|
int scale = 1;
|
||||||
SP<IHLBuffer> buffer;
|
SP<CHLBufferReference> buffer; // buffer ref will be released once the buffer is no longer locked. For checking if a buffer is attached to this state, check texture.
|
||||||
SP<CTexture> texture;
|
SP<CTexture> texture;
|
||||||
Vector2D offset;
|
Vector2D offset;
|
||||||
Vector2D size;
|
Vector2D size, bufferSize;
|
||||||
struct {
|
struct {
|
||||||
bool hasDestination = false;
|
bool hasDestination = false;
|
||||||
bool hasSource = false;
|
bool hasSource = false;
|
||||||
|
@ -116,7 +116,7 @@ class CWLSurfaceResource {
|
||||||
std::vector<WP<CMonitor>> enteredOutputs;
|
std::vector<WP<CMonitor>> enteredOutputs;
|
||||||
bool mapped = false;
|
bool mapped = false;
|
||||||
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
|
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
|
||||||
WP<ISurfaceRole> role;
|
SP<ISurfaceRole> role;
|
||||||
WP<CViewportResource> viewportResource;
|
WP<CViewportResource> viewportResource;
|
||||||
WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
|
WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
|
||||||
|
|
||||||
|
@ -134,12 +134,21 @@ class CWLSurfaceResource {
|
||||||
SP<CWlSurface> resource;
|
SP<CWlSurface> resource;
|
||||||
wl_client* pClient = nullptr;
|
wl_client* pClient = nullptr;
|
||||||
|
|
||||||
int stateLocks = 0;
|
// this is for cursor dumb copy. Due to our (and wayland's...) architecture,
|
||||||
|
// this stupid-ass hack is used
|
||||||
|
WP<IHLBuffer> lastBuffer;
|
||||||
|
|
||||||
void destroy();
|
int stateLocks = 0;
|
||||||
void releaseBuffers(bool onlyCurrent = true);
|
|
||||||
void commitPendingState();
|
void destroy();
|
||||||
void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
void releaseBuffers(bool onlyCurrent = true);
|
||||||
|
void dropPendingBuffer();
|
||||||
|
void dropCurrentBuffer();
|
||||||
|
void commitPendingState();
|
||||||
|
void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
||||||
|
void updateCursorShm();
|
||||||
|
|
||||||
|
friend class CWLPointerResource;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CWLCompositorResource {
|
class CWLCompositorResource {
|
||||||
|
|
|
@ -469,12 +469,12 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
|
||||||
if (dragSurface) {
|
if (dragSurface) {
|
||||||
dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); });
|
dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); });
|
||||||
dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) {
|
dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) {
|
||||||
if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) {
|
if (dnd.dndSurface->current.texture && !dnd.dndSurface->mapped) {
|
||||||
dnd.dndSurface->map();
|
dnd.dndSurface->map();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) {
|
if (dnd.dndSurface->current.texture <= 0 && dnd.dndSurface->mapped) {
|
||||||
dnd.dndSurface->unmap();
|
dnd.dndSurface->unmap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -660,13 +660,13 @@ void CWLDataDeviceProtocol::abortDrag() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
|
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
|
||||||
if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture)
|
if (!dnd.dndSurface || !dnd.dndSurface->current.texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto POS = g_pInputManager->getMouseCoordsInternal();
|
const auto POS = g_pInputManager->getMouseCoordsInternal();
|
||||||
|
|
||||||
CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale);
|
CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale);
|
||||||
g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F);
|
g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.texture, &box, 1.F);
|
||||||
|
|
||||||
box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
|
box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
|
||||||
g_pHyprRenderer->damageBox(&box);
|
g_pHyprRenderer->damageBox(&box);
|
||||||
|
|
|
@ -119,7 +119,19 @@ CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResou
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY});
|
auto surfResource = surf ? CWLSurfaceResource::fromResource(surf) : nullptr;
|
||||||
|
|
||||||
|
if (surfResource && surfResource->role->role() != SURFACE_ROLE_CURSOR && surfResource->role->role() != SURFACE_ROLE_UNASSIGNED) {
|
||||||
|
r->error(-1, "Cursor surface already has a different role");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surfResource) {
|
||||||
|
surfResource->role = makeShared<CCursorSurfaceRole>();
|
||||||
|
surfResource->updateCursorShm();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pSeatManager->onSetCursor(owner.lock(), serial, surfResource, {hotX, hotY});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client())
|
if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client())
|
||||||
|
@ -546,3 +558,10 @@ SP<CWLSeatResource> CWLSeatProtocol::seatResourceForClient(wl_client* client) {
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t>& CCursorSurfaceRole::cursorPixelData(SP<CWLSurfaceResource> surface) {
|
||||||
|
RASSERT(surface->role->role() == SURFACE_ROLE_CURSOR, "cursorPixelData called on a non-cursor surface");
|
||||||
|
|
||||||
|
auto role = (CCursorSurfaceRole*)surface->role.get();
|
||||||
|
return role->cursorShmPixelData;
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "wayland.hpp"
|
#include "wayland.hpp"
|
||||||
#include "../../helpers/signal/Signal.hpp"
|
#include "../../helpers/signal/Signal.hpp"
|
||||||
#include "../../helpers/math/Math.hpp"
|
#include "../../helpers/math/Math.hpp"
|
||||||
|
#include "../types/SurfaceRole.hpp"
|
||||||
|
|
||||||
constexpr const char* HL_SEAT_NAME = "Hyprland";
|
constexpr const char* HL_SEAT_NAME = "Hyprland";
|
||||||
|
|
||||||
|
@ -27,6 +28,20 @@ class CWLKeyboardResource;
|
||||||
class CWLTouchResource;
|
class CWLTouchResource;
|
||||||
class CWLSeatResource;
|
class CWLSeatResource;
|
||||||
|
|
||||||
|
class CCursorSurfaceRole : public ISurfaceRole {
|
||||||
|
public:
|
||||||
|
virtual eSurfaceRole role() {
|
||||||
|
return SURFACE_ROLE_CURSOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets the current pixel data from a shm surface
|
||||||
|
// will assert if the surface is not a cursor
|
||||||
|
static std::vector<uint8_t>& cursorPixelData(SP<CWLSurfaceResource> surface);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> cursorShmPixelData;
|
||||||
|
};
|
||||||
|
|
||||||
class CWLTouchResource {
|
class CWLTouchResource {
|
||||||
public:
|
public:
|
||||||
CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_);
|
CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_);
|
||||||
|
|
|
@ -80,13 +80,13 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP<CWlSubsurface> resource_, SP<CWL
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
||||||
if (surface->current.buffer && !surface->mapped) {
|
if (surface->current.texture && !surface->mapped) {
|
||||||
surface->map();
|
surface->map();
|
||||||
surface->events.map.emit();
|
surface->events.map.emit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->current.buffer && surface->mapped) {
|
if (!surface->current.texture && surface->mapped) {
|
||||||
surface->events.unmap.emit();
|
surface->events.unmap.emit();
|
||||||
surface->unmap();
|
surface->unmap();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#include "Buffer.hpp"
|
#include "Buffer.hpp"
|
||||||
|
|
||||||
|
IHLBuffer::~IHLBuffer() {
|
||||||
|
if (locked() && resource)
|
||||||
|
sendRelease();
|
||||||
|
}
|
||||||
|
|
||||||
void IHLBuffer::sendRelease() {
|
void IHLBuffer::sendRelease() {
|
||||||
resource->sendRelease();
|
resource->sendRelease();
|
||||||
}
|
}
|
||||||
|
@ -8,3 +13,54 @@ void IHLBuffer::sendReleaseWithSurface(SP<CWLSurfaceResource> surf) {
|
||||||
if (resource && resource->good())
|
if (resource && resource->good())
|
||||||
resource->sendReleaseWithSurface(surf);
|
resource->sendReleaseWithSurface(surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IHLBuffer::lock() {
|
||||||
|
nLocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHLBuffer::unlock() {
|
||||||
|
nLocks--;
|
||||||
|
|
||||||
|
ASSERT(nLocks >= 0);
|
||||||
|
|
||||||
|
if (nLocks == 0)
|
||||||
|
sendRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHLBuffer::unlockWithSurface(SP<CWLSurfaceResource> surf) {
|
||||||
|
nLocks--;
|
||||||
|
|
||||||
|
ASSERT(nLocks >= 0);
|
||||||
|
|
||||||
|
if (nLocks == 0)
|
||||||
|
sendReleaseWithSurface(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IHLBuffer::locked() {
|
||||||
|
return nLocks > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHLBuffer::unlockOnBufferRelease(WP<CWLSurfaceResource> surf) {
|
||||||
|
unlockSurface = surf;
|
||||||
|
hlEvents.backendRelease = events.backendRelease.registerListener([this](std::any data) {
|
||||||
|
if (unlockSurface.expired())
|
||||||
|
unlock();
|
||||||
|
else
|
||||||
|
unlockWithSurface(unlockSurface.lock());
|
||||||
|
hlEvents.backendRelease.reset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CHLBufferReference::CHLBufferReference(SP<IHLBuffer> buffer_, SP<CWLSurfaceResource> surface_) : buffer(buffer_), surface(surface_) {
|
||||||
|
buffer->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHLBufferReference::~CHLBufferReference() {
|
||||||
|
if (buffer.expired())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (surface)
|
||||||
|
buffer->unlockWithSurface(surface.lock());
|
||||||
|
else
|
||||||
|
buffer->unlock();
|
||||||
|
}
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
class IHLBuffer : public Aquamarine::IBuffer {
|
class IHLBuffer : public Aquamarine::IBuffer {
|
||||||
public:
|
public:
|
||||||
virtual ~IHLBuffer() {
|
virtual ~IHLBuffer();
|
||||||
;
|
|
||||||
}
|
|
||||||
virtual Aquamarine::eBufferCapability caps() = 0;
|
virtual Aquamarine::eBufferCapability caps() = 0;
|
||||||
virtual Aquamarine::eBufferType type() = 0;
|
virtual Aquamarine::eBufferType type() = 0;
|
||||||
virtual void update(const CRegion& damage) = 0;
|
virtual void update(const CRegion& damage) = 0;
|
||||||
|
@ -18,6 +16,12 @@ class IHLBuffer : public Aquamarine::IBuffer {
|
||||||
virtual bool good() = 0;
|
virtual bool good() = 0;
|
||||||
virtual void sendRelease();
|
virtual void sendRelease();
|
||||||
virtual void sendReleaseWithSurface(SP<CWLSurfaceResource>);
|
virtual void sendReleaseWithSurface(SP<CWLSurfaceResource>);
|
||||||
|
virtual void lock();
|
||||||
|
virtual void unlock();
|
||||||
|
virtual void unlockWithSurface(SP<CWLSurfaceResource> surf);
|
||||||
|
virtual bool locked();
|
||||||
|
|
||||||
|
void unlockOnBufferRelease(WP<CWLSurfaceResource> surf /* optional */);
|
||||||
|
|
||||||
SP<CTexture> texture;
|
SP<CTexture> texture;
|
||||||
bool opaque = false;
|
bool opaque = false;
|
||||||
|
@ -26,4 +30,22 @@ class IHLBuffer : public Aquamarine::IBuffer {
|
||||||
struct {
|
struct {
|
||||||
CHyprSignalListener backendRelease;
|
CHyprSignalListener backendRelease;
|
||||||
} hlEvents;
|
} hlEvents;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int nLocks = 0;
|
||||||
|
|
||||||
|
WP<CWLSurfaceResource> unlockSurface;
|
||||||
|
};
|
||||||
|
|
||||||
|
// for ref-counting. Releases in ~dtor
|
||||||
|
// surface optional
|
||||||
|
class CHLBufferReference {
|
||||||
|
public:
|
||||||
|
CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
|
||||||
|
~CHLBufferReference();
|
||||||
|
|
||||||
|
WP<IHLBuffer> buffer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WP<CWLSurfaceResource> surface;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ enum eSurfaceRole {
|
||||||
SURFACE_ROLE_LAYER_SHELL,
|
SURFACE_ROLE_LAYER_SHELL,
|
||||||
SURFACE_ROLE_EASTER_EGG,
|
SURFACE_ROLE_EASTER_EGG,
|
||||||
SURFACE_ROLE_SUBSURFACE,
|
SURFACE_ROLE_SUBSURFACE,
|
||||||
|
SURFACE_ROLE_CURSOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISurfaceRole {
|
class ISurfaceRole {
|
||||||
|
|
|
@ -29,7 +29,6 @@ bool CWLBufferResource::good() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLBufferResource::sendRelease() {
|
void CWLBufferResource::sendRelease() {
|
||||||
released = true;
|
|
||||||
resource->sendRelease();
|
resource->sendRelease();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@ class CWLBufferResource {
|
||||||
|
|
||||||
WP<CWLBufferResource> self;
|
WP<CWLBufferResource> self;
|
||||||
|
|
||||||
bool released = false;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWLBufferResource(SP<CWlBuffer> resource_);
|
CWLBufferResource(SP<CWlBuffer> resource_);
|
||||||
|
|
||||||
|
|
|
@ -102,10 +102,10 @@ CHyprRenderer::~CHyprRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* data) {
|
static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* data) {
|
||||||
if (!surface->current.buffer || !surface->current.buffer->texture)
|
if (!surface->current.texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto& TEXTURE = surface->current.buffer->texture;
|
const auto& TEXTURE = surface->current.texture;
|
||||||
const auto RDATA = (SRenderData*)data;
|
const auto RDATA = (SRenderData*)data;
|
||||||
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE;
|
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE;
|
||||||
|
|
||||||
|
@ -192,8 +192,8 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
|
||||||
windowBox.round();
|
windowBox.round();
|
||||||
|
|
||||||
const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
|
const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
|
||||||
windowBox.size() != surface->current.buffer->size /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.buffer->size.x, 3) &&
|
windowBox.size() != surface->current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.bufferSize.x, 3) &&
|
||||||
DELTALESSTHAN(windowBox.height, surface->current.buffer->size.y, 3) /* off by one-or-two */ &&
|
DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ &&
|
||||||
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
|
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
|
||||||
|
|
||||||
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1);
|
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1);
|
||||||
|
@ -1014,7 +1014,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
|
||||||
|
|
||||||
if (pSurface->current.viewport.hasSource) {
|
if (pSurface->current.viewport.hasSource) {
|
||||||
// we stretch it to dest. if no dest, to 1,1
|
// we stretch it to dest. if no dest, to 1,1
|
||||||
Vector2D bufferSize = pSurface->current.buffer->size;
|
Vector2D bufferSize = pSurface->current.bufferSize;
|
||||||
auto bufferSource = pSurface->current.viewport.source;
|
auto bufferSource = pSurface->current.viewport.source;
|
||||||
|
|
||||||
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
|
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
|
||||||
|
@ -1030,8 +1030,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
|
||||||
if (projSize != Vector2D{} && fixMisalignedFSV1) {
|
if (projSize != Vector2D{} && fixMisalignedFSV1) {
|
||||||
// instead of nearest_neighbor (we will repeat / skip)
|
// instead of nearest_neighbor (we will repeat / skip)
|
||||||
// just cut off / expand surface
|
// just cut off / expand surface
|
||||||
const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.buffer->size;
|
const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.bufferSize;
|
||||||
const Vector2D MISALIGNMENT = pSurface->current.buffer->size - projSize;
|
const Vector2D MISALIGNMENT = pSurface->current.bufferSize - projSize;
|
||||||
if (MISALIGNMENT != Vector2D{})
|
if (MISALIGNMENT != Vector2D{})
|
||||||
uvBR -= MISALIGNMENT * PIXELASUV;
|
uvBR -= MISALIGNMENT * PIXELASUV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer) {
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_bOpaque = buffer->opaque;
|
||||||
|
|
||||||
auto attrs = buffer->dmabuf();
|
auto attrs = buffer->dmabuf();
|
||||||
|
|
||||||
if (!attrs.success) {
|
if (!attrs.success) {
|
||||||
|
@ -86,6 +88,7 @@ void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bOpaque = FormatUtils::isFormatOpaque(attrs.format);
|
||||||
m_iTarget = GL_TEXTURE_2D;
|
m_iTarget = GL_TEXTURE_2D;
|
||||||
m_iType = TEXTURE_RGBA;
|
m_iType = TEXTURE_RGBA;
|
||||||
m_vSize = attrs.size;
|
m_vSize = attrs.size;
|
||||||
|
|
|
@ -41,6 +41,7 @@ class CTexture {
|
||||||
Vector2D m_vSize = {};
|
Vector2D m_vSize = {};
|
||||||
void* m_pEglImage = nullptr;
|
void* m_pEglImage = nullptr;
|
||||||
eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
|
eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
|
||||||
|
bool m_bOpaque = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
|
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
|
||||||
|
|
|
@ -62,12 +62,12 @@ void CXWaylandSurface::ensureListeners() {
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
||||||
if (surface->pending.buffer && !mapped) {
|
if (surface->pending.texture && !mapped) {
|
||||||
map();
|
map();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->pending.buffer && mapped) {
|
if (!surface->pending.texture && mapped) {
|
||||||
unmap();
|
unmap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ void CXWaylandSurface::considerMap() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->pending.buffer) {
|
if (surface->pending.texture) {
|
||||||
Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer");
|
Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer");
|
||||||
map();
|
map();
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue