Skip to content

Commit 4e77270

Browse files
committed
Improved, faster Pipewire + option to disable EGL
1 parent d2900bd commit 4e77270

File tree

12 files changed

+660
-332
lines changed

12 files changed

+660
-332
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2020-2025 awawa-dev
3+
Copyright (c) 2020-2026 awawa-dev
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

cmake/cmake_modules/FindQmqtt.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2020-2025 awawa-dev
1+
# Copyright (c) 2020-2026 awawa-dev
22
if (NOT WIN32)
33
if (QMQTT_LIBRARIES AND QMQTT_INCLUDE_DIRS)
44
set(QMQTT_FOUND TRUE)

cmake/osx/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2020-2025 awawa-dev
3+
Copyright (c) 2020-2026 awawa-dev
44

55
Permission is hereby granted, free of charge, to any person
66
obtaining a copy of this software and associated documentation

include/grabber/linux/pipewire/PipewireHandler.h

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <QDebug>
34
#include <QObject>
45
#include <QVector>
56
#include <QList>
@@ -13,8 +14,11 @@
1314
#include <spa/debug/types.h>
1415
#include <grabber/linux/pipewire/smartPipewire.h>
1516
#include <linux/types.h>
17+
#include <sys/mman.h>
1618
#include <HyperhdrConfig.h>
1719
#include <memory>
20+
#include <atomic>
21+
#include <array>
1822

1923
#if !PW_CHECK_VERSION(0, 3, 29)
2024
#define SPA_POD_PROP_FLAG_MANDATORY (1u << 3)
@@ -40,16 +44,25 @@ typedef EGLBoolean (*eglDestroyImageKHRFun)(EGLDisplay dpy, EGLImageKHR image);
4044
typedef EGLContext(*eglCreateContextFun)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint* attrib_list);
4145
typedef EGLBoolean(*eglDestroyContextFun)(EGLDisplay display, EGLContext context);
4246
typedef EGLBoolean(*eglMakeCurrentFun)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
47+
typedef EGLContext(*eglGetCurrentContextFun)(void);
4348
typedef EGLBoolean(*eglBindAPIFun)(EGLenum api);
4449
typedef void (*glEGLImageTargetTexture2DOESFun)(GLenum target, GLeglImageOES image);
4550

46-
typedef void* (*glXGetProcAddressARBFun)(const char*);
4751
typedef void (*glBindTextureFun)(GLenum target, GLuint texture);
4852
typedef void (*glDeleteTexturesFun)(GLsizei n, const GLuint* textures);
4953
typedef void (*glGenTexturesFun)(GLsizei n, GLuint* textures);
5054
typedef GLenum (*glGetErrorFun)(void);
5155
typedef void (*glGetTexImageFun)(GLenum target, GLint level, GLenum format, GLenum type, void* pixels);
5256
typedef void (*glTexParameteriFun)(GLenum target, GLenum pname, GLint param);
57+
typedef void (*glGenerateMipmapFun)(GLenum target);
58+
typedef void (*glPixelStoreiFun)(GLenum pname,GLint param);
59+
typedef void (*glGenFramebuffersFun)(GLsizei n, GLuint* ids);
60+
typedef void (*glBindFramebufferFun)(GLenum target, GLuint framebuffer);
61+
typedef void (*glFramebufferTexture2DFun)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
62+
typedef void (*glReadPixelsFun)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data);
63+
typedef void (*glDeleteFramebuffersFun)(GLsizei n, GLuint* framebuffers);
64+
typedef void (*glBlitFramebufferFun)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
65+
typedef void (*glTexImage2DFun)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data);
5366

5467
#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
5568
((__u32)(c) << 16) | ((__u32)(d) << 24))
@@ -79,14 +92,18 @@ class PipewireHandler : public QObject
7992

8093
PipewireHandler();
8194
~PipewireHandler();
82-
void startSession(QString restorationToken, uint32_t requestedFPS);
95+
96+
void startSession(QString restorationToken, uint32_t requestedFPS, bool enableEGL, int targetMaxSize);
8397
void closeSession();
8498
bool hasError();
8599

86100
int getVersion();
87101
QString getToken();
88102
QString getError();
89103

104+
pw_stream* getPipewireStream();
105+
bool hasIncomingFrame(struct pw_buffer* dequeueFrame);
106+
90107
static int readVersion();
91108

92109
struct PipewireStructure
@@ -107,6 +124,7 @@ public Q_SLOTS:
107124
void onStateChanged(enum pw_stream_state old, enum pw_stream_state state, const char* error);
108125
void onProcessFrame();
109126
void onCoreError(uint32_t id, int seq, int res, const char *message);
127+
void onReleaseBuffer(struct pw_buffer* buffer);
110128

111129
signals:
112130
void onParamsChangedSignal(uint32_t id, const struct spa_pod* param);
@@ -117,7 +135,7 @@ public Q_SLOTS:
117135
private:
118136
uint8_t* createMemory(int size);
119137
void reportError(const QString& input);
120-
const QString fourCCtoString(int64_t val);
138+
QString fourCCtoString(int64_t val);
121139

122140
pw_stream* createCapturingStream();
123141
QString getSessionToken();
@@ -146,14 +164,15 @@ public Q_SLOTS:
146164
struct pw_buffer* _backupFrame;
147165
struct pw_buffer* _workingFrame;
148166

167+
int _targetMaxSize;
149168
int _frameWidth;
150169
int _frameHeight;
151170
bool _frameOrderRgb;
152-
bool _framePaused;
153171
uint32_t _requestedFPS;
154-
bool _hasFrame;
155-
bool _infoUpdated;
172+
std::atomic<struct pw_buffer*> _incomingFrame;
173+
int _infoUpdate;
156174
bool _initEGL;
175+
bool _enableEGL;
157176
void* _libEglHandle;
158177
void* _libGlHandle;
159178
int64_t _frameDrmFormat;
@@ -181,19 +200,31 @@ public Q_SLOTS:
181200
eglCreateContextFun eglCreateContext = nullptr;
182201
eglDestroyContextFun eglDestroyContext = nullptr;
183202
eglMakeCurrentFun eglMakeCurrent = nullptr;
203+
eglGetCurrentContextFun eglGetCurrentContext = nullptr;
184204
glEGLImageTargetTexture2DOESFun glEGLImageTargetTexture2DOES = nullptr;
185205
eglBindAPIFun eglBindAPI = nullptr;
186206

187-
glXGetProcAddressARBFun glXGetProcAddressARB = nullptr;
188207
glBindTextureFun glBindTexture = nullptr;
189208
glDeleteTexturesFun glDeleteTextures = nullptr;
190209
glGenTexturesFun glGenTextures = nullptr;
191210
glGetErrorFun glGetError = nullptr;
192211
glGetTexImageFun glGetTexImage = nullptr;
193212
glTexParameteriFun glTexParameteri = nullptr;
213+
glGenerateMipmapFun glGenerateMipmap = nullptr;
214+
glPixelStoreiFun glPixelStorei = nullptr;
215+
glGenFramebuffersFun glGenFramebuffers = nullptr;
216+
glBindFramebufferFun glBindFramebuffer = nullptr;
217+
glFramebufferTexture2DFun glFramebufferTexture2D = nullptr;
218+
glReadPixelsFun glReadPixels = nullptr;
219+
glDeleteFramebuffersFun glDeleteFramebuffers = nullptr;
220+
glBlitFramebufferFun glBlitFramebuffer = nullptr;
221+
glTexImage2DFun glTexImage2D = nullptr;
194222

195223
EGLDisplay displayEgl = EGL_NO_DISPLAY;
196224
EGLContext contextEgl = EGL_NO_CONTEXT;
225+
GLuint _eglTexture = 0;
226+
GLuint _eglScratchTex = 0;
227+
std::array<GLuint, 2> _eglFbos = { 0, 0 };
197228

198229
const char* eglErrorToString(EGLint error_number);
199230
const char* glErrorToString(GLenum errorType);
@@ -214,7 +245,16 @@ public Q_SLOTS:
214245
{ DRM_FORMAT_XBGR8888, SPA_VIDEO_FORMAT_RGBx, GL_RGBA, "DRM_FORMAT_XBGR8888", false},
215246
{ DRM_FORMAT_ABGR8888, SPA_VIDEO_FORMAT_RGBA, GL_RGBA, "DRM_FORMAT_ABGR8888", false}
216247
};
217-
218248
#endif
219249

250+
struct PipewireCache {
251+
252+
#ifdef ENABLE_PIPEWIRE_EGL
253+
EGLImageKHR eglImage = EGL_NO_IMAGE_KHR;
254+
#endif
255+
256+
void* mmapPtr = MAP_FAILED;
257+
size_t mmapSize = 0;
258+
259+
};
220260
};

include/grabber/linux/pipewire/smartPipewire.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct PipewireImage
1313
extern "C" const char* getPipewireToken();
1414
extern "C" const char* getPipewireError();
1515
extern "C" bool hasPipewire();
16-
extern "C" void initPipewireDisplay(const char* restorationToken, uint32_t requestedFPS);
16+
extern "C" void initPipewireDisplay(const char* restorationToken, uint32_t requestedFPS, bool enableEGL, int targetMaxSize);
1717
extern "C" void uninitPipewireDisplay();
1818
extern "C" PipewireImage getFramePipewire();
1919
extern "C" void releaseFramePipewire();

sources/base/schema/schema-systemGrabber.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"type" : "integer",
3030
"format": "stepper",
3131
"title" : "edt_conf_stream_framerate_title",
32-
"default" : 10,
32+
"default" : 20,
3333
"minimum" : 5,
3434
"maximum" : 120,
3535
"append" : "fps",

sources/grabber/linux/pipewire/PipewireGrabber.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* MIT License
44
*
5-
* Copyright (c) 2020-2025 awawa-dev
5+
* Copyright (c) 2020-2026 awawa-dev
66
*
77
* Project homesite: https://github.com/awawa-dev/HyperHDR
88
*
@@ -53,7 +53,7 @@ namespace
5353
{
5454
bool (*_hasPipewire)() = nullptr;
5555
const char* (*_getPipewireError)() = nullptr;
56-
void (*_initPipewireDisplay)(const char* restorationToken, uint32_t requestedFPS) = nullptr;
56+
void (*_initPipewireDisplay)(const char* restorationToken, uint32_t requestedFPS, bool enableEGL, int targetMaxSize) = nullptr;
5757
void (*_uninitPipewireDisplay)() = nullptr;
5858
PipewireImage(*_getFramePipewire)() = nullptr;
5959
void (*_releaseFramePipewire)() = nullptr;
@@ -81,7 +81,7 @@ PipewireGrabber::PipewireGrabber(const QString& device, const QString& configura
8181
_getPipewireToken = (const char* (*)()) dlsym(_library, "getPipewireToken");
8282
_getPipewireError = (const char* (*)()) dlsym(_library, "getPipewireError");
8383
_hasPipewire = (bool (*)()) dlsym(_library, "hasPipewire");
84-
_initPipewireDisplay = (void (*)(const char*, uint32_t)) dlsym(_library, "initPipewireDisplay");
84+
_initPipewireDisplay = (void (*)(const char*, uint32_t, bool, int)) dlsym(_library, "initPipewireDisplay");
8585
_uninitPipewireDisplay = (void (*)()) dlsym(_library, "uninitPipewireDisplay");
8686
_getFramePipewire = (PipewireImage (*)()) dlsym(_library, "getFramePipewire");
8787
_releaseFramePipewire = (void (*)()) dlsym(_library, "releaseFramePipewire");
@@ -154,7 +154,7 @@ void PipewireGrabber::uninit()
154154
Debug(_log, "Uninit grabber: {:s}", (_deviceName));
155155
}
156156

157-
157+
_isActive = false;
158158
_initialized = false;
159159
}
160160

@@ -263,12 +263,12 @@ void PipewireGrabber::stop()
263263
{
264264
_timer.stop();
265265

266-
_uninitPipewireDisplay();
267-
_isActive = false;
266+
_uninitPipewireDisplay();
268267
_initialized = false;
269268

270269
Info(_log, "Stopped");
271270
}
271+
_isActive = false;
272272
}
273273

274274
bool PipewireGrabber::init_device(int _display)
@@ -282,14 +282,9 @@ bool PipewireGrabber::init_device(int _display)
282282
token = "";
283283
else
284284
Info(_log, "Loading restoration token: {:s}", (maskToken(token)));
285-
_initPipewireDisplay(token.toLatin1().constData(), _fps);
286-
287-
_isActive = true;
288-
289-
if (!_isActive)
290-
Error(_log, "Could not initialized Pipewire grabber");
285+
_initPipewireDisplay(token.toLatin1().constData(), _fps, _hardware, _width);
291286

292-
return _isActive;
287+
return true;
293288
}
294289

295290
QString PipewireGrabber::maskToken(const QString& token) const
@@ -319,7 +314,7 @@ void PipewireGrabber::grabFrame()
319314
bool stopNow = false;
320315

321316

322-
if (_initialized && _isActive)
317+
if (_initialized)
323318
{
324319
PipewireImage data = _getFramePipewire();
325320

@@ -360,6 +355,7 @@ void PipewireGrabber::grabFrame()
360355
}
361356
else
362357
{
358+
_isActive = true;
363359
_actualWidth = data.width;
364360
_actualHeight = data.height;
365361

@@ -374,7 +370,19 @@ void PipewireGrabber::grabFrame()
374370

375371
if (stopNow)
376372
{
373+
bool lastActive = _isActive;
377374
uninit();
375+
_isActive = lastActive;
376+
if (_isActive)
377+
{
378+
QTimer::singleShot(3000, this, [this]() {
379+
if (_isActive)
380+
{
381+
_isActive = false;
382+
start();
383+
}
384+
});
385+
}
378386
}
379387
}
380388

0 commit comments

Comments
 (0)