core/syncobjtimeline: make explicit sync use SYNC_IOC_MERGE instead of waiting on the CPU side
This brings some performance benefits, because the application can potentially reuse the buffer earlier, and it simplifies the code a bit
This commit is contained in:
parent
32addf4d59
commit
4c6000b3e1
4 changed files with 67 additions and 35 deletions
|
@ -6,8 +6,24 @@
|
|||
#include "syncobjtimeline.h"
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include <linux/sync_file.h>
|
||||
#else
|
||||
struct sync_merge_data
|
||||
{
|
||||
char name[32];
|
||||
__s32 fd2;
|
||||
__s32 fence;
|
||||
__u32 flags;
|
||||
__u32 pad;
|
||||
};
|
||||
#define SYNC_IOC_MAGIC '>'
|
||||
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
|
||||
#endif
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -19,7 +35,39 @@ SyncReleasePoint::SyncReleasePoint(const std::shared_ptr<SyncTimeline> &timeline
|
|||
|
||||
SyncReleasePoint::~SyncReleasePoint()
|
||||
{
|
||||
m_timeline->signal(m_timelinePoint);
|
||||
if (m_releaseFence.isValid()) {
|
||||
m_timeline->moveInto(m_timelinePoint, m_releaseFence);
|
||||
} else {
|
||||
m_timeline->signal(m_timelinePoint);
|
||||
}
|
||||
}
|
||||
|
||||
static FileDescriptor mergeSyncFds(const FileDescriptor &fd1, const FileDescriptor &fd2)
|
||||
{
|
||||
struct sync_merge_data data
|
||||
{
|
||||
.name = "merged release fence",
|
||||
.fd2 = fd2.get(),
|
||||
.fence = -1,
|
||||
};
|
||||
int err = -1;
|
||||
do {
|
||||
err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data);
|
||||
} while (err == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
if (err < 0) {
|
||||
return FileDescriptor{};
|
||||
} else {
|
||||
return FileDescriptor(data.fence);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncReleasePoint::addReleaseFence(const FileDescriptor &fd)
|
||||
{
|
||||
if (m_releaseFence.isValid()) {
|
||||
m_releaseFence = mergeSyncFds(m_releaseFence, fd);
|
||||
} else {
|
||||
m_releaseFence = fd.duplicate();
|
||||
}
|
||||
}
|
||||
|
||||
SyncTimeline *SyncReleasePoint::timeline() const
|
||||
|
@ -60,17 +108,8 @@ void SyncTimeline::signal(uint64_t timelinePoint)
|
|||
drmSyncobjTimelineSignal(m_drmFd, &m_handle, &timelinePoint, 1);
|
||||
}
|
||||
|
||||
SyncReleasePointHolder::SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set<std::shared_ptr<SyncReleasePoint>> &&releasePoints)
|
||||
: m_fence(std::move(requirement))
|
||||
, m_notifier(m_fence.get(), QSocketNotifier::Type::Read)
|
||||
, m_releasePoints(std::move(releasePoints))
|
||||
void SyncTimeline::moveInto(uint64_t timelinePoint, const FileDescriptor &fd)
|
||||
{
|
||||
connect(&m_notifier, &QSocketNotifier::activated, this, &SyncReleasePointHolder::signaled);
|
||||
m_notifier.setEnabled(true);
|
||||
}
|
||||
|
||||
void SyncReleasePointHolder::signaled()
|
||||
{
|
||||
delete this;
|
||||
drmSyncobjImportSyncFile(m_drmFd, m_handle, fd.get());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
#include "kwin_export.h"
|
||||
#include "utils/filedescriptor.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSocketNotifier>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -30,9 +27,16 @@ public:
|
|||
SyncTimeline *timeline() const;
|
||||
uint64_t timelinePoint() const;
|
||||
|
||||
/**
|
||||
* Adds the fence of a graphics job that this release point should wait for
|
||||
* before the timeline point is signaled
|
||||
*/
|
||||
void addReleaseFence(const FileDescriptor &fd);
|
||||
|
||||
private:
|
||||
const std::shared_ptr<SyncTimeline> m_timeline;
|
||||
const uint64_t m_timelinePoint;
|
||||
FileDescriptor m_releaseFence;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT SyncTimeline
|
||||
|
@ -47,26 +51,10 @@ public:
|
|||
FileDescriptor eventFd(uint64_t timelinePoint) const;
|
||||
|
||||
void signal(uint64_t timelinePoint);
|
||||
void moveInto(uint64_t timelinePoint, const FileDescriptor &fd);
|
||||
|
||||
private:
|
||||
const int32_t m_drmFd;
|
||||
const uint32_t m_handle;
|
||||
};
|
||||
|
||||
class SyncReleasePointHolder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @param requirement the filedescriptor that needs to be readable before the release points may be signalled. Once that's happened, this object deletes itself!'
|
||||
*/
|
||||
explicit SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set<std::shared_ptr<SyncReleasePoint>> &&releasePoints);
|
||||
|
||||
private:
|
||||
void signaled();
|
||||
|
||||
const FileDescriptor m_fence;
|
||||
QSocketNotifier m_notifier;
|
||||
const std::unordered_set<std::shared_ptr<SyncReleasePoint>> m_releasePoints;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -53,7 +53,10 @@ void ItemRendererOpenGL::endFrame()
|
|||
if (m_eglDisplay) {
|
||||
EGLNativeFence fence(m_eglDisplay);
|
||||
if (fence.isValid()) {
|
||||
new SyncReleasePointHolder(std::move(fence.fileDescriptor()), std::move(m_releasePoints));
|
||||
for (const auto &releasePoint : m_releasePoints) {
|
||||
releasePoint->addReleaseFence(fence.fileDescriptor());
|
||||
}
|
||||
m_releasePoints.clear();
|
||||
}
|
||||
}
|
||||
m_releasePoints.clear();
|
||||
|
|
|
@ -344,8 +344,10 @@ public:
|
|||
void setPreferredColorDescription(const ColorDescription &descr);
|
||||
|
||||
/**
|
||||
* @returns the release point that should be referenced as long as the buffer on this surface
|
||||
* is, or may still be used by the compositor
|
||||
* Returns the current release point for the buffer on this surface. The buffer keeps the
|
||||
* release point referenced as long as it's referenced itself; for synchronization on the
|
||||
* GPU side, the compositor has to either keep the release point referenced as long as the
|
||||
* GPU task is running, or add a fence for each GPU task to the release point
|
||||
*/
|
||||
std::shared_ptr<SyncReleasePoint> bufferReleasePoint() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue