Skip to content

Commit 767d93b

Browse files
committed
wait on dmabuf buffers to be readable
1 parent dc43097 commit 767d93b

File tree

3 files changed

+85
-9
lines changed

3 files changed

+85
-9
lines changed

src/protocols/core/Compositor.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
#include "../../helpers/sync/SyncReleaser.hpp"
1111
#include "../PresentationTime.hpp"
1212
#include "../DRMSyncobj.hpp"
13+
#include "../types/DMABuffer.hpp"
1314
#include "../../render/Renderer.hpp"
1415
#include "config/ConfigValue.hpp"
16+
#include "../../managers/eventLoop/EventLoopManager.hpp"
1517
#include "protocols/types/SurfaceRole.hpp"
1618
#include "render/Texture.hpp"
1719
#include <cstring>
@@ -123,16 +125,15 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
123125
return;
124126
}
125127

126-
if ((!pending.updated.buffer) || // no new buffer attached
127-
(!pending.buffer && !pending.texture) || // null buffer attached
128-
(!pending.updated.acquire && pending.buffer->isSynchronous()) // synchronous buffers (ex. shm) can be read immediately
128+
if ((!pending.updated.buffer) || // no new buffer attached
129+
(!pending.buffer && !pending.texture) // null buffer attached
129130
) {
130131
commitState(pending);
131132
pending.reset();
132133
return;
133134
}
134135

135-
// save state while we wait for buffer to become ready
136+
// save state while we wait for buffer to become ready to read
136137
const auto& state = pendingStates.emplace(makeUnique<SSurfaceState>(pending));
137138
pending.reset();
138139

@@ -152,13 +153,19 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
152153
if (state->updated.acquire) {
153154
// wait on acquire point for this surface, from explicit sync protocol
154155
state->acquire.addWaiter(whenReadable);
155-
} else if (state->buffer->dmabuf().success) {
156-
// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#implicit-fence-poll-support
157-
// TODO: wait for the dma-buf fd's to become readable
156+
} else if (state->buffer->isSynchronous()) {
157+
// synchronous (shm) buffers can be read immediately
158158
whenReadable();
159+
} else if (state->buffer->type() == Aquamarine::BUFFER_TYPE_DMABUF && state->buffer->dmabuf().success) {
160+
// async buffer and is dmabuf, then we can wait on implicit fences
161+
auto syncFd = dynamic_cast<CDMABuffer*>(state->buffer.buffer.get())->exportSyncFile();
162+
163+
if (syncFd.isValid())
164+
g_pEventLoopManager->doOnReadable(std::move(syncFd), whenReadable);
165+
else
166+
whenReadable();
159167
} else {
160-
// huh??? only buffers with acquire or dmabuf should get through here...
161-
Debug::log(ERR, "BUG THIS: wl_surface.commit: non-acquire non-dmabuf buffers needs wait...");
168+
Debug::log(ERR, "BUG THIS: wl_surface.commit: no acquire, non-dmabuf, async buffer, needs wait... this shouldn't happen");
162169
whenReadable();
163170
}
164171
});

src/protocols/types/DMABuffer.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
#include "../../render/Renderer.hpp"
55
#include "../../helpers/Format.hpp"
66

7+
#if defined(__linux__)
8+
#include <linux/dma-buf.h>
9+
#include <linux/sync_file.h>
10+
#include <sys/ioctl.h>
11+
#endif
12+
13+
using namespace Hyprutils::OS;
14+
715
CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) {
816
g_pHyprRenderer->makeEGLCurrent();
917

@@ -84,3 +92,62 @@ void CDMABuffer::closeFDs() {
8492
}
8593
attrs.planes = 0;
8694
}
95+
96+
static int doIoctl(int fd, unsigned long request, void* arg) {
97+
int ret;
98+
99+
do {
100+
ret = ioctl(fd, request, arg);
101+
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
102+
return ret;
103+
}
104+
105+
// https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_buf_export_sync_file
106+
// returns a sync file that will be signalled when dmabuf is ready to be read
107+
CFileDescriptor CDMABuffer::exportSyncFile() {
108+
if (!good())
109+
return {};
110+
111+
#if !defined(__linux__)
112+
return {};
113+
#else
114+
std::vector<CFileDescriptor> syncFds(attrs.fds.size());
115+
for (const auto& fd : attrs.fds) {
116+
if (fd == -1)
117+
continue;
118+
119+
dma_buf_export_sync_file request{
120+
.flags = DMA_BUF_SYNC_READ,
121+
.fd = -1,
122+
};
123+
124+
if (doIoctl(fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &request) == 0)
125+
syncFds.emplace_back(request.fd);
126+
}
127+
128+
if (syncFds.empty())
129+
return {};
130+
131+
CFileDescriptor syncFd;
132+
for (auto& fd : syncFds) {
133+
if (!syncFd.isValid()) {
134+
syncFd = std::move(fd);
135+
continue;
136+
}
137+
138+
struct sync_merge_data data{
139+
.name = "merged release fence",
140+
.fd2 = fd.get(),
141+
.fence = -1,
142+
};
143+
144+
if (doIoctl(syncFd.get(), SYNC_IOC_MERGE, &data) == 0) {
145+
syncFd = CFileDescriptor(data.fence);
146+
} else {
147+
syncFd = {};
148+
}
149+
}
150+
151+
return syncFd;
152+
#endif
153+
}

src/protocols/types/DMABuffer.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "Buffer.hpp"
4+
#include <hyprutils/os/FileDescriptor.hpp>
45

56
class CDMABuffer : public IHLBuffer {
67
public:
@@ -16,6 +17,7 @@ class CDMABuffer : public IHLBuffer {
1617
virtual void endDataPtr();
1718
bool good();
1819
void closeFDs();
20+
Hyprutils::OS::CFileDescriptor exportSyncFile();
1921

2022
bool success = false;
2123

0 commit comments

Comments
 (0)