core: wait for dmabuf readiness (#9806)
* add doOnReadable to event loop manager * move syncTimeline addWaiter to doOnReadable * wait on dmabuf buffers to be readable * don't over synchronize in scanout, also give present feedback on same buffer commit
This commit is contained in:
parent
ffd6cf65e4
commit
0e521788bc
8 changed files with 147 additions and 116 deletions
|
|
@ -10,8 +10,10 @@
|
|||
#include "../../helpers/sync/SyncReleaser.hpp"
|
||||
#include "../PresentationTime.hpp"
|
||||
#include "../DRMSyncobj.hpp"
|
||||
#include "../types/DMABuffer.hpp"
|
||||
#include "../../render/Renderer.hpp"
|
||||
#include "config/ConfigValue.hpp"
|
||||
#include "../../managers/eventLoop/EventLoopManager.hpp"
|
||||
#include "protocols/types/SurfaceRole.hpp"
|
||||
#include "render/Texture.hpp"
|
||||
#include <cstring>
|
||||
|
|
@ -123,16 +125,15 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||
return;
|
||||
}
|
||||
|
||||
if ((!pending.updated.buffer) || // no new buffer attached
|
||||
(!pending.buffer && !pending.texture) || // null buffer attached
|
||||
(!pending.updated.acquire && pending.buffer->isSynchronous()) // synchronous buffers (ex. shm) can be read immediately
|
||||
if ((!pending.updated.buffer) || // no new buffer attached
|
||||
(!pending.buffer && !pending.texture) // null buffer attached
|
||||
) {
|
||||
commitState(pending);
|
||||
pending.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// save state while we wait for buffer to become ready
|
||||
// save state while we wait for buffer to become ready to read
|
||||
const auto& state = pendingStates.emplace(makeUnique<SSurfaceState>(pending));
|
||||
pending.reset();
|
||||
|
||||
|
|
@ -152,13 +153,19 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
|||
if (state->updated.acquire) {
|
||||
// wait on acquire point for this surface, from explicit sync protocol
|
||||
state->acquire.addWaiter(whenReadable);
|
||||
} else if (state->buffer->dmabuf().success) {
|
||||
// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#implicit-fence-poll-support
|
||||
// TODO: wait for the dma-buf fd's to become readable
|
||||
} else if (state->buffer->isSynchronous()) {
|
||||
// synchronous (shm) buffers can be read immediately
|
||||
whenReadable();
|
||||
} else if (state->buffer->type() == Aquamarine::BUFFER_TYPE_DMABUF && state->buffer->dmabuf().success) {
|
||||
// async buffer and is dmabuf, then we can wait on implicit fences
|
||||
auto syncFd = dynamic_cast<CDMABuffer*>(state->buffer.buffer.get())->exportSyncFile();
|
||||
|
||||
if (syncFd.isValid())
|
||||
g_pEventLoopManager->doOnReadable(std::move(syncFd), whenReadable);
|
||||
else
|
||||
whenReadable();
|
||||
} else {
|
||||
// huh??? only buffers with acquire or dmabuf should get through here...
|
||||
Debug::log(ERR, "BUG THIS: wl_surface.commit: non-acquire non-dmabuf buffers needs wait...");
|
||||
Debug::log(ERR, "BUG THIS: wl_surface.commit: no acquire, non-dmabuf, async buffer, needs wait... this shouldn't happen");
|
||||
whenReadable();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@
|
|||
#include "../../render/Renderer.hpp"
|
||||
#include "../../helpers/Format.hpp"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/sync_file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) {
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
|
|
@ -84,3 +92,61 @@ void CDMABuffer::closeFDs() {
|
|||
}
|
||||
attrs.planes = 0;
|
||||
}
|
||||
|
||||
static int doIoctl(int fd, unsigned long request, void* arg) {
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = ioctl(fd, request, arg);
|
||||
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file
|
||||
// returns a sync file that will be signalled when dmabuf is ready to be read
|
||||
CFileDescriptor CDMABuffer::exportSyncFile() {
|
||||
if (!good())
|
||||
return {};
|
||||
|
||||
#if !defined(__linux__)
|
||||
return {};
|
||||
#else
|
||||
std::vector<CFileDescriptor> syncFds(attrs.fds.size());
|
||||
for (const auto& fd : attrs.fds) {
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
dma_buf_export_sync_file request{
|
||||
.flags = DMA_BUF_SYNC_READ,
|
||||
.fd = -1,
|
||||
};
|
||||
|
||||
if (doIoctl(fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &request) == 0)
|
||||
syncFds.emplace_back(request.fd);
|
||||
}
|
||||
|
||||
if (syncFds.empty())
|
||||
return {};
|
||||
|
||||
CFileDescriptor syncFd;
|
||||
for (auto& fd : syncFds) {
|
||||
if (!syncFd.isValid()) {
|
||||
syncFd = std::move(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sync_merge_data data{
|
||||
.name = "merged release fence",
|
||||
.fd2 = fd.get(),
|
||||
.fence = -1,
|
||||
};
|
||||
|
||||
if (doIoctl(syncFd.get(), SYNC_IOC_MERGE, &data) == 0)
|
||||
syncFd = CFileDescriptor(data.fence);
|
||||
else
|
||||
syncFd = {};
|
||||
}
|
||||
|
||||
return syncFd;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include <hyprutils/os/FileDescriptor.hpp>
|
||||
|
||||
class CDMABuffer : public IHLBuffer {
|
||||
public:
|
||||
|
|
@ -16,6 +17,7 @@ class CDMABuffer : public IHLBuffer {
|
|||
virtual void endDataPtr();
|
||||
bool good();
|
||||
void closeFDs();
|
||||
Hyprutils::OS::CFileDescriptor exportSyncFile();
|
||||
|
||||
bool success = false;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue