Linux port: Vulkan/X11/Wayland rendering backend#525
Linux port: Vulkan/X11/Wayland rendering backend#525alansley wants to merge 28 commits intoe-dream-ai:masterfrom
Conversation
Ten standalone bug fixes that are correct on all platforms. Each was a
latent bug on macOS masked by libc++/GLUT/Metal; they surface as hard
errors on Linux/libstdc++/Vulkan.
- Common/SmartPtr.h: guard _LIBCPP_INLINE_VISIBILITY — libstdc++ does
not define _LIBCPP_HIDE_FROM_ABI, so the macro expansion failed to
compile on GCC.
- Common/BlockingQueue.h: condition_variable::wait() requires a lock
object, not a raw mutex. Three call sites passed m_mutex directly
(undefined behaviour). Also mark condition var members mutable so
const methods can legally call wait().
- Common/XTimer.h: remove unused <X11/Xlib.h> / <X11/Xutil.h> —
these headers define the None macro (0L) which clashes with
enum class TransitionType { None }. Also make Time() const to
satisfy the ITimer pure-virtual signature.
- Client/FrameDisplay.h: guard <CoreVideo/CVPixelBuffer.h> inside
#ifdef MAC — CoreVideo does not exist on Linux.
- Client/StringFormat.cpp: add missing #include <cstdarg> for
va_list / va_start / va_end.
- Client/client.h: wrap SHAREDIR in std::string() when calling
Set("settings.app.InstallDir", ...). SHAREDIR is const char*; without
the cast, overload resolution picks Set(string_view, bool) (non-null
pointer → true) instead of Set(string_view, string_view), storing a
boolean in JSON and crashing later at as_string().
- ContentDecoder/ContentDecoder.cpp: avcodec_close() was removed in
FFmpeg 6.x. Replace with avcodec_free_context() which also nulls the
pointer.
- ContentDownloader/PlaylistManager.h: add missing <condition_variable>
and <mutex> for the std::condition_variable / std::mutex members.
- DisplayOutput/Renderer/TextureFlat.h: wrap FFmpeg headers in
extern "C". Without it, sws_getContext gets C++ name mangling and
fails to link even with -lswscale present.
- Networking/EDreamClient.h: add missing SetQuota() declaration.
The method is defined in EDreamClient.cpp and called from a free
function, but was absent from the header, causing a compile error
on strict-conformance builds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Modify existing files to route Linux through Vulkan instead of falling through to Metal (which only exists on macOS). No Mac code paths are changed — all additions are inside new #elif defined(LINUX_GNU) or #else branches that were previously absent or broken. - Client/Player.cpp: change bare #else after WIN32 guard to #elif defined(MAC) for Metal includes, add new #else block that includes DisplayVulkan.h / RendererVulkan.h. AddDisplay() gains a matching Linux branch that constructs CDisplayVulkan + CRendererVulkan. Remove dead EndFrameUpdate() FPS-capping code (spFD / m_PlayerFps undefined on Linux; the block was never reachable on Mac either due to the surrounding #ifndef USE_METAL guard). - Client/main.cpp: remove <GL/gl.h> / <GL/glut.h> includes from the Linux branch (Vulkan does not use GLUT). Guard glutInit() inside #if defined(MAC) so it is not called on Linux. - Client/client_linux.h: remove #include "lua_playlist.h" (file does not exist). Add #include "PlatformUtils.h". Fix m_AppData path to ~/.config/infinidream/. Derive m_WorkingDir from PlatformUtils::GetWorkingDir() rather than the autotools SHAREDIR macro. Fix g_Player().AddDisplay() missing nullptr second argument. Remove g_Player().Framerate() call (method no longer exists). Fix CElectricSheep::Update() call to pass required int argument. Replace invalid static_cast<spCKeyEvent> with std::static_pointer_cast. Remove entire stale voting block (m_pVoter, GetCurrentPlayingID, RepeatSheep, m_spSplashPos/Neg — all removed from current codebase). - Client/cpu_usage_linux.h: replace glibtop (GNOME library, requires libgtop2 which is not a standard dependency) with direct /proc/stat parsing. ReadProcStat() uses fscanf with a format string that matches the literal "cpu" prefix — no throwaway variables, no string allocation, returns matched == 4 on success. GetNumCores() uses sysconf(_SC_NPROCESSORS_ONLN) instead of parsing /proc/cpuinfo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Everything needed to configure and compile the project on Linux.
No existing Mac build files are touched.
LinuxBuild/CMakeLists.txt
Standalone CMake build for Linux (mirrors MacBuild structure).
Targets: Vulkan, X11, Boost (filesystem/thread/log/log_setup/json),
FFmpeg (via pkg-config), OpenSSL, libcurl, libpng, pthreads.
Compiles GLSL shaders to SPIR-V via glslc (from Vulkan SDK or PATH)
and copies them next to the binary at POST_BUILD. Defines LINUX_GNU,
BOOST_FILESYSTEM_VERSION=3, SHAREDIR=".".
LinuxBuild/PlatformUtils_Linux.cpp
Implements the PlatformUtils static interface for Linux:
IsInternetReachable (connect to 8.8.8.8:53), GetWorkingDir / GetAppPath
(/proc/self/exe), OpenURLExternally (xdg-open), SetThreadName
(pthread_setname_np), SetCursorHidden (X11 blank cursor),
SetOnMouseMovedCallback, DispatchOnMainThread (thread-safe queue
drained on the main thread), NotifyError (stderr), CalculateFileMD5
(OpenSSL EVP — same logic as the Mac version).
LinuxBuild/PlatformUtils_Internal.h
Internal helpers shared between DisplayVulkan and PlatformUtils_Linux:
DrainMainThreadQueue(), GetMouseCallback(), GetCursorHidden().
socket.io-client-cpp/lib/linux/libsioclient{,_tls}.a
Linux ELF builds of socket.io-client-cpp. The vendored .a files in
lib/ are Mach-O universal binaries used by the Xcode project and are
left untouched. Linux links against the lib/linux/ variants via CMake.
To rebuild: clone socket.io-client-cpp, cmake -DUSE_TLS=1, make.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New DisplayOutput/Vulkan/ directory implements the CDisplayOutput and
CRenderer interfaces for Linux using Vulkan + X11. The Metal backend
(DisplayOutput/Metal/) is untouched.
DisplayVulkan (.h/.cpp)
Creates an X11 Window and a VkSurfaceKHR via VK_KHR_xlib_surface.
Manages VkInstance, VkDevice (picks first discrete GPU, falls back to
integrated), VkSwapchainKHR, render pass, framebuffers, and per-frame
sync primitives (semaphores + fence). Fullscreen via EWMH
_NET_WM_STATE_FULLSCREEN. Handles ConfigureNotify resize by
recreating the swapchain. XScreensaver mode: if XSCREENSAVER_WINDOW
env var is set the window is reparented into it rather than created
standalone. Implements CDisplayOutput: Initialize, Resize, SetTitle,
SetFullScreen, Present, SwapBuffers, ProcessEvents.
RendererVulkan (.h/.cpp)
Implements CRenderer. Allocates a VkDescriptorPool, descriptor set
layout, and a graphics pipeline backed by the compiled quad shaders.
Per-frame: acquires swapchain image, begins render pass, binds
pipeline + descriptor set, draws the fullscreen quad, ends pass,
submits, presents. BeginFrame/EndFrame bracket each rendered frame.
NewTextureFlat() returns a CTextureFlatVulkan.
TextureFlatVulkan (.h/.cpp)
Implements CTextureFlat. Allocates a VkImage + VkImageView + VkSampler
and a host-visible VkDeviceMemory staging buffer. Upload(spCImage)
copies RGBA pixel data via vkMapMemory then transitions the image to
SHADER_READ_ONLY_OPTIMAL. BindFrame(spCVideoFrame) maps decoded AVFrame
data directly into the staging buffer each frame for zero-copy video
upload. The descriptor set is updated with vkUpdateDescriptorSets so
the fragment shader samples the current frame.
ShaderVulkan (.h/.cpp)
Loads SPIR-V bytecode (compiled from shaders/quad.vert / quad.frag at
build time by glslc). Creates VkShaderModule.
FontVulkan (.h/.cpp)
Stub implementing CFont. Text rendering is not yet wired up on Linux;
the stub satisfies the interface so the binary links and runs.
shaders/quad.vert
Fullscreen triangle-pair. Passes UV coordinates to the fragment stage.
shaders/quad.frag
Samples a combined image sampler (the current video frame texture)
and writes to the swapchain image. YUV→RGB conversion is handled
upstream by FFmpeg swscale (frames arrive as RGBA); the shader is a
straight passthrough blit.
Verified on Arch Linux, RTX 4090, Vulkan 1.4.341, driver 575.57.08:
cmake -B build -DCMAKE_BUILD_TYPE=Debug && cmake --build build
./build/infinidream → window opens, content decoder and downloader
initialise, video playback begins.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
At runtime, if WAYLAND_DISPLAY is set and XSCREENSAVER_WINDOW is not, DisplayVulkan connects natively to the Wayland compositor using VK_KHR_wayland_surface instead of VK_KHR_xlib_surface. XScreensaver embed mode always uses X11 (that protocol is inherently X11). On X11-only systems or if wayland-client is absent at build time, behaviour is identical to before. CMakeLists.txt: Optionally find wayland-client, wayland-protocols, and wayland-scanner via pkg-config. When all three are present, generates xdg-shell protocol bindings (xdg-shell-protocol.c / xdg-shell-client-protocol.h) at configure time via wayland-scanner, adds HAVE_WAYLAND compile definition, and links wayland-client. Graceful fallback to X11-only if any piece is missing. DisplayVulkan.h / .cpp: createVulkanInstance() picks VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME or VK_KHR_XLIB_SURFACE_EXTENSION_NAME based on m_bWayland. initWayland() — connects to wl_display, binds wl_compositor and xdg_wm_base from the registry, creates wl_surface, xdg_surface, and xdg_toplevel, handles ping/configure/close via static listener callbacks (onXdgWmBasePing, onXdgSurfaceConfigure, onXdgToplevelConfigure, onXdgToplevelClose), sets fullscreen if requested, and does two wl_display_roundtrips to complete the initial configure handshake before returning. checkEvents() dispatches Wayland events with wl_display_flush() + wl_display_dispatch_pending() instead of XPending/XNextEvent. setFullScreen() calls xdg_toplevel_set_fullscreen / _unset_fullscreen on Wayland; EWMH ClientMessage on X11. Title() calls xdg_toplevel_set_title on Wayland; XStoreName on X11. destroyWayland() tears down xdg_toplevel → xdg_surface → wl_surface → xdg_wm_base → wl_compositor → wl_display in dependency order, after Vulkan surface/instance are already destroyed. client_linux.h: Replace CElectricSheep::Update(0) (now requires two boost::barrier refs) with the equivalent direct calls: BeginFrameUpdate(), DoRealFrameUpdate(0), EndFrameUpdate(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EDreamClient::ParsePlaylist line 1631 passed a std::string_view to a %s variadic argument. On Apple Clang/libc++ this accidentally works because the ABI passes the pointer field first and it happens to be null-terminated; on GCC/libstdc++ vsnprintf reads the struct bytes differently and segfaults. Fix: uuid.empty() ? "default playlist" : uuid.data() uuid.data() is safe here — callers always pass a std::string-backed view so the data pointer is null-terminated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Frame.h: set m_pFrame->format/width/height in first constructor (was left as AV_PIX_FMT_NONE=-1, causing sws_getContext to crash) - Clip.cpp: use AV_PIX_FMT_RGBA on Linux so ContentDecoder pre-converts decoded frames; call BindFrame via USE_HW_ACCELERATION||LINUX_GNU guard - TextureFlatVulkan: add Bind() override to set descriptor set on renderer; add dirty flag so Apply() re-binds after each BindFrame upload; fast-path RGBA upload without redundant swscale pass - RendererVulkan: Apply() was a no-op stub — delegate to base class so texture Bind()/Dirty() logic actually runs - quad.vert: input coords are normalized [0,1], not pixels — remove division by screenWidth/Height that squashed quad to a 1px strip - websocketpp/constants.hpp: bump max_header_size 16KB→64KB for Heroku large set-cookie response headers - libsioclient_tls.a: rebuild with patched websocketpp header - client.h: fix Run() loop and add virtual Update() base - EDreamClient.cpp: fix string_view passed to %s (UB on GCC) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ipts The Mac build (primary platform) uses Xcode/CMake and is unaffected. These files were remnants of the original Electric Sheep Linux autotools era: - electricsheep-saver, electricsheep-saver-gnome: wrapper scripts pointing at an 'electricsheep' binary that no longer exists. Linux xscreensaver integration already works via the XSCREENSAVER_WINDOW env var in DisplayVulkan — no wrapper script needed. - Makefile.am (root, Client/, MSVC/SettingsGUI/), configure.ac, Makefile.in: dead autotools scaffolding superseded by LinuxBuild/CMakeLists.txt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two targeted fixes for the high CPU usage observed on Linux (~57% CPU for simple video playback). RendererVulkan: switch swapchain from MAILBOX to FIFO present mode. MAILBOX never blocks — vkQueuePresentKHR returns immediately and the render loop spins at uncapped speed consuming a full CPU core. FIFO is guaranteed supported by the Vulkan spec and blocks on each present until the next vblank, giving vsync-throttled output for free with zero extra code. Mac is unaffected (Vulkan backend is Linux-only). client.h / Player.h: call FpsCap(m_PerceptualFPS) in the Run() loop after each frame. FpsCap() already existed in Player.cpp (complete with its own wall-clock timer) but was unreachable — it was buried inside a WIN32-only private section. Move it to public and call it from Run(), which caps frame delivery to the configured perceptual FPS (default 20 fps) and sleeps away any remaining frame budget. Run() is only entered from main.cpp on Linux; the Mac Cocoa/display- link loop never calls it, so Mac behaviour is unchanged. Together these changes eliminate the busy-spin that was burning ~30-40% of a CPU core between frames and the uncapped GPU submission loop on top. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The existing auth flow only knew how to refresh a WorkOS sealed session
(wos-session cookie). On Linux there is no UI to obtain one, so a fresh
install could never authenticate.
The backend middleware already accepts an Api-Key <key> header as an
alternative to the session cookie on all protected endpoints, so no
server changes are needed.
Changes:
EDreamClient: AppendAuthHeader()
Centralises all request auth in one place. Previously every call site
duplicated three lines of get-setting / build-header / append-header.
Now: sealed session present → Cookie: wos-session=<session> (existing
behaviour); no session but api_key present → Api-Key <key>; neither →
no auth header (request will 401, existing error handling applies).
All ~15 call sites replaced with AppendAuthHeader(spDownload).
EDreamClient: SignInWithApiKey()
Persists the API key to settings.content.api_key and returns true.
No round-trip to the server needed — the key is used directly on each
subsequent request.
EDreamClient: Authenticate() fallback
After sealed-session refresh fails, checks the INFINIDREAM_API_KEY
environment variable. If set, calls SignInWithApiKey() and persists
the key for future runs. Falls back to a key already stored in
settings. This means Linux users can authenticate with:
export INFINIDREAM_API_KEY=<key> ./infinidream
or by adding settings.content.api_key to ~/.electricsheep/settings.json.
WebSocket connection
ConnectRemoteControlSocket() now passes Api-Key in the query map when
no sealed session is available, matching the HTTP auth fallback.
Mac is unaffected: EDreamClient is shared but the Mac flow always
obtains a sealed session via the first-time setup UI before reaching
any of these paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The streaming-load lambda (detached thread that fetches a download link and starts a clip) declared a bool return type via an early 'return false' on the no-display-units error path, but fell off the end without returning on the success path. Add 'return true' after the clip-start block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three related issues with the startup/loading screen on Linux: client.h: startup screen invisible during buffering The render block was gated on (drawNoSheepIntro || drawn). When a clip is in buffering mode g_Player().Update() returns false (drawn=false), and if the user is logged in HasStarted() is true so drawNoSheepIntro is also false. Result: nothing rendered at all — pure black screen while waiting for the first frames to decode. Fix: hoist the startup-screen visibility check into a 'showStartup' bool and include it in the outer gate condition so the startup screen renders independently of whether the player has a frame ready to draw. StartupScreen.h: white square when logo.png not found CImage::Create() initialises the 256×256 buffer to white. If Load() fails (file not found) the blank white image was still uploaded as a texture and rendered as a white square in the centre of the screen. Fix: check the return value of Load() and set m_spImageRef = nullptr on failure. The existing if (m_spImageRef) guard around the DrawQuad then cleanly skips the logo without affecting the text rendering below it. CMakeLists.txt: deploy logo.png next to the binary at build time The startup screen looks for logo.png relative to the working directory (settings.app.InstallDir). On Linux this is the build output directory, but the asset was never copied there. Add a POST_BUILD custom command that copies Runtime/logo.png next to the infinidream binary so it is found on first launch without manual installation steps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HasStarted() returns true as soon as the playlist is set in the startup thread, which happens before the first render frame. This meant drawNoSheepIntro=false and m_StartupScreen was never created, so showStartup=false and drawn=false → pure black screen. Fix: include !drawn in the showStartup condition so the startup screen is shown whenever there is no video frame available yet (buffering, quota exhausted, no content downloaded, etc.) regardless of whether HasStarted() returned true. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On Wayland, vkAcquireNextImageKHR returns VK_ERROR_OUT_OF_DATE_KHR after the first few frames during initial surface configuration. Previously BeginFrame() returned false without recreating the swapchain, causing BeginDisplayFrame() to return false every subsequent frame. Since Player::Update() is gated on BeginDisplayFrame(), it was never called, so Clip::Update() never ran, the buffering threshold was never checked, the frame queue filled to max (25 frames), and the decoder thread blocked on push() — meaning video never played. Fix: store the VkSurfaceKHR in Initialize(), implement recreateSwapchain() (wait idle → destroy framebuffers/imageviews/swapchain → recreate), and call it from both BeginFrame() and EndFrame() on OUT_OF_DATE or SUBOPTIMAL. Also: - Return bool from RenderFrame() so Update() can report whether it drew - Fix SHAREDIR path suffix (\"./\" instead of \".\") in CMakeLists.txt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Example Linux output: The frame-rate hitches / hiccups in the video are from OBS - they didn't occur live and everything was smooth. |
…isc fixes
Fullscreen / windowed toggle (Wayland):
- Add F key binding to toggle fullscreen (replaces Ctrl+F) in client_linux.h
- Add key-release guard (m_bPressed check) to prevent double-fire on toggle actions
- Add ToggleFullscreen() virtual to DisplayOutput base; override in CDisplayVulkan
- Set m_bFullScreen = bFullscreen in initWayland before the initial roundtrip so
the configure-event filter correctly accepts the startup fullscreen configure
- Parse XDG_TOPLEVEL_STATE_FULLSCREEN from the wl_array in onXdgToplevelConfigure
and ignore stale fullscreen configures when we have already requested windowed mode
- Set m_Width/m_Height = 1280x720 in setFullScreen(false) before unset_fullscreen
so RendererVulkan recreates the swapchain at the correct windowed size
- Re-assert ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE on windowed transition
- Add proactive swapchain recreation in BeginFrame when display dimensions change
(Wayland compositors do not always send VK_ERROR_OUT_OF_DATE_KHR for client-driven
resizes)
- Add xdg-decoration-unstable-v1 protocol support (server-side window borders);
falls back gracefully when the compositor does not advertise the interface (GNOME)
- Log all Wayland registry globals at startup for diagnostics
- Update CMakeLists.txt to generate xdg-decoration protocol bindings via
wayland-scanner alongside the existing xdg-shell bindings
VAAPI / video decoder fixes:
- Fix VAAPI PTS loss: av_hwframe_transfer_data copies only pixel data; manually
copy pts, pkt_dts, and best_effort_timestamp to sw_frame before av_frame_move_ref
- Guard against corrupted/wrapped last_played_frame resume values (e.g. uint32_t
wrap from a previous VAAPI PTS bug) by clamping seekFrame to a sane range
Font / HUD rendering (FontVulkan):
- Implement FreeType-based glyph atlas for Vulkan (CFontVulkan)
- Wire up TextureFlatVulkan for font atlas texture upload
Startup / display:
- Fix startup screen visibility: show logo until the first video frame is ready
- Silence spurious PNG warnings for Mac-only OSD assets missing on Linux by
removing the Warning log from the file-not-found path in LoadPNG.cpp
HUD / help text (client.h):
- Capitalise all F1 help text entries ("A: Slower playback" not "a: slower…")
- Show "F: Toggle full screen" on Linux instead of "Ctrl+F: Toggle full screen"
README: update Linux build and feature documentation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- client.h: make BK() macro a no-op on non-Linux builds; the \x01/\x02 inline-bold markers are only handled by the Linux HUD renderer — on Mac they would appear as raw control characters in the F1 help overlay - ContentDecoder.cpp: change #ifndef WIN32 guards to #ifdef LINUX_GNU so the VAAPI code (vaapi_get_format, hw device init, hw frame transfer) is only compiled on Linux; Mac retains its VideoToolbox path via the existing USE_HW_ACCELERATION / USE_METAL logic in base.h Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Text rendering from commit: 28d0d82 |
Remove the FreeType-based CFontVulkan/CTextVulkan implementation and replace it with ImGui-backed CFontImGui/CTextImGui, using ImGui's embedded ProggyForever font (MIT licensed, no external font files required). New build dependency: Dear ImGui added as a git submodule at client_generic/imgui (pinned to v1.92.6, the latest stable release). Its source files are compiled directly into the Linux build — no system package or vcpkg entry needed. - Drop FreeType dependency from LinuxBuild/CMakeLists.txt - CFontImGui: registers font with ImGui atlas via AddFontDefaultVector() - CTextImGui: GetExtent() measures via CalcTextSizeA() - RendererVulkan: integrate ImGui frame lifecycle (NewFrame/Render/RenderDrawData) - DrawText: segment-based renderer handles \n (newlines) and \t (tab stops at 4×space width); \x01/\x02 bold markers are stripped — ProggyForever has no bold variant so bold text support is removed for now pending a future decision on font strategy - Remove Lato-Regular.ttf from the build (was missing its license) - Update README: remove freetype2 from prereqs, note ImGui submodule init No Mac files were modified. The Metal renderer, Mac CMakeLists, OSD, and CI workflow are all unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Build worked, but it doesn't launch on my Arch X11 system with integrated graphics (Intel). |
Thanks for the report - I'll take a look at it on the weekend. |
|
Got it working with this diff, it was AI generated, so I am sure there is a better way, but it might be useful for your real fix. =) |
X11 fullscreen / window management: - Create window at requested size and apply _NET_WM_STATE_FULLSCREEN as a window *property* before mapping (not a client message), so the WM resizes it to the correct monitor dimensions on startup. - MapNotify wait loop now captures ConfigureNotify events so the initial fullscreen size is known before creating the Vulkan surface/swapchain. - Add 500 ms fallback poll if ConfigureNotify arrives after MapNotify. - Fix EWMH setFullScreen message: data.l[0] must be 0/1, not an Atom value; set data.l[2]=0, data.l[3]=1 (source: normal application). - checkEvents(): update m_Width/m_Height on ConfigureNotify so HUD coordinates stay in sync with WM-driven window resizes at runtime. - Add IsWayland() accessor to CDisplayVulkan. Swapchain / HUD aspect ratio: - createSwapchain(): use std::clamp(requested, min, max) instead of caps.currentExtent, which can lag behind ConfigureNotify on X11. - BeginFrame(): trigger swapchain recreation when Display()->Width/Height() differs from m_swapExtent, replacing the surface-caps query that had the same lag problem. - Set io.DisplaySize from Display()->Width/Height() so ImGui always reflects the true window dimensions. - Remove max(1.0f, ...) floor from font scaling in DrawText, GetExtent, StatsConsole, and StartupScreen; use proportional screenH/1080 scaling. - Compute startup logo aspect ratio dynamically each frame rather than baking it in the constructor, fixing logo squash after fullscreen toggle. F1 help overlay: - Remove inline bold markers (\x01/\x02) from BK macro — ProggyForever does not support bold; simplify DrawText and GetExtent accordingly. - Fix tab stop counts so all right-column key bindings align correctly. Auth: - On InvalidSession refresh failure, probe the QUOTA endpoint before wiping the session; HTTP 200 means the token is still live and the client proceeds logged in rather than forcing an unnecessary re-login. - Companion backend change: e-dream-ai/backend#407 Misc: remove unused boost::bind include from Player.cpp. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…efactor Upstream added richer result types (SendCodeResult, ValidateCodeResult, HelloResult) and a retry loop in GetCurrentServerPlaylist(). Conflict was in HelloDetailed(): kept our AppendAuthHeader() call (which handles both wos-session cookie and Api-Key header for Linux/headless) in place of the sealed-session-only block from upstream. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
X11 adjustments made in 9384f5b now allow the client to work correctly in Wayland and X11 - tested on X11 under xfce:
@zquestz - thanks for the diff - that was helpful & much appreciated! =D @scottdraves I'm seeing an issue where sometimes changing from full-screen to windowed then showing the F1 help or F2 status text will sometimes draw the text-backing semi-transparent rectangle as an ellipse for a little while before something "catches up" and it displays as a rectangle again (happens most frequently near startup), but I don't think it's a deal-breaker and can be handled in another PR when I have the energy & patience for it! |
|
awesome. yes i saw that ellipse on mac when i was optimizing the Metal drawing and shaders & claude fixed it: |
CRendererVulkan::Reset() was a complete no-op, so calling it with eTexture never cleared m_aspSelectedTextures[]. Apply() then re-bound the stale video/startup texture, causing DrawSoftQuad to sample it instead of the white descriptor set — manifesting as a ghost ellipse behind the F1 help and F2 status overlays. Fix: delegate to CRenderer::Reset(_flags) so the base class clears m_aspSelectedTextures, then explicitly reset m_currentDescSet to m_whiteDescSet when eTexture is requested. Inspired by upstream commit 29a5da8 (e-dream-ai/client), which fixed the same class of stale-texture bug on Metal by clearing stale bindings between draw calls that share a single render encoder. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@alansley sure, with the input I was just curious if you had the same experience or if it was a result of me using kanata for input remapping. are you manually setting a value in |
|
I was unable to use an API key as well. I had to use an existing session. |
|
@zquestz that did it, thanks for the pointer! |
|
You can launch with an API key via: |
|
I'm using the environment variable, but I got a black screen and the session issue shown in the log I shared. the client plays dreams successfully when, in addition to the env var API key, I supply an existing session ID as a value in |
|
@wolfwood - fair enough, thanks for the details, I'll look into it. |
This is the behavior I see as well. |
|
cool! i got a box set up &\ was able to build and run pretty easily on ubuntu. however i didn't have easy access to a sealed session from another machine, so i didn't get any videos. |
|
@scottdraves you can grab a session cookie by visiting https://api-alpha.infinidream.ai/api/v1/client/hello in a browser that is logged in to infinidream and then using the Web Developer Tools -> storage tab -> cookies. it's the value for the key |
|
yea it works if i copy it from a browser, then it downloads and displays at a really low frame rate. |
…g path
- Add LoginWithMagicLinkCode(): on first run prompts for email (saved to
settings.generator.nickname), sends a one-time code, reads it from stdin,
and exchanges it for a sealed session before the window opens. Subsequent
runs auto-refresh the session; re-prompts interactively if it expires.
- Add --cached flag: skips auth entirely and plays locally cached videos in
offline mode, reporting count and size ("cycling through N (X.X GB) of
cached videos"). Exits with a clear message if the cache is empty.
- Pre-check auth state before the display window opens: if no sealed session
and no API key, attempt magic link login or abort with actionable guidance
rather than opening a window that cannot download any content.
- Store api_key and user email in settings.json (settings.content.api_key /
settings.generator.nickname) rather than a separate credentials file.
- Fix Linux settings path: remove hardcoded ~/.electricsheep/ in InitStorage()
so settings, logs, and content all live under ~/.config/infinidream/ as
client_linux.h always intended.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Added interactive login flow to obtain sealed session token if missing - 283742a
I'm not sure why it's doing 20 FPS, but I'd prefer to investigate that as a separate issue. |
|
great, will try later. The "decoding video at" 20.0 fps is correct, that's just the default. |
|
The sign-in flow worked, awesome :) if we could get sync with infinidream's playback for extra smoothness that would be awesome but yea, it might require a little push. but even without that, i am seeing really poor display, i think it started out at 10-20fps but slowed down to ~5 after a bit. |
|
Log has: Previously when it initialized Vulkan it said: |
Sounds like it might be thermal throttling due to the CPU-based video decoding. You can try a Hail-Mary fix first if you want - it's not going to break anything any worse. For example, try forcing the modern iHD video driver in case you're on the legacy i965 driver: Or unset the LIBVA_DRIVER_NAME in case whatever's currently set is wrong: If that doesn't get the hardware video decoding back...
2.) Figure out what the current setup is (outputs details to Let me know what the above says and I can look into it - or give that info to Claude or ChatGPT - they can help figure stuff out, too. |
|
just had to do and the error goes away, |
The Linux client was doing too much synchronous work on the main/render loop for what should be a mostly idle video screensaver workload. In particular, the shared client frame path was repeatedly probing internet reachability, rebuilding cache statistics, polling download/network status, and updating large HUD/stat blocks every frame. On Linux that showed up as excessive CPU usage even when hardware video decode was active, and it also created extra event-pump churn because the Linux wrapper called Display()->Update() a second time each frame. This change introduces a cached RuntimeDiagnostics layer inside CElectricSheep so the expensive shared-loop diagnostics are sampled on coarse timers instead of per frame. Fast-changing values such as CPU, GPU, and transfer status are refreshed at a short interval, while slower values such as internet reachability, disk/update status, and cache size are refreshed at longer intervals. The dream stats and credits HUD updates are also gated on HUD visibility so hidden overlays no longer pay the full per-frame formatting and data collection cost. An optional INFINIDREAM_PERF_LOG path remains available for coarse runtime measurements. On Linux specifically, the extra Display()->Update() call in CElectricSheep_Linux::Update() is removed so window events are pumped once per frame through the shared render path instead of twice. That reduces unnecessary X11/Wayland work without changing presentation semantics. This is intentionally safe for macOS because it does not change the Metal renderer, macOS display update path, swap/present behavior, or decode pipeline. The shared-code changes only reduce how often diagnostic state is recomputed and how often hidden HUDs are updated. Visible HUD behavior remains intact, user-triggered network checks still force a fresh connectivity probe, and the Linux-only event-pump change is isolated to client_linux.h.
|
The main thread's very busy and doing a lot of work per-frame that doesn't need to be per-frame - fixed in: 994b1a9 Try rebuilding with the above commit then run: My before stats: My after stats: |
Wayland windowed mode previously relied entirely on xdg-decoration server-side decorations. On compositors that do not provide that protocol, the Linux client came up undecorated, which left the window difficult to move and resize compared with the existing X11 path. Add an optional libdecor-0 fallback in the Vulkan display backend and Linux build. When xdg-decoration is unavailable, the Wayland path now creates a libdecor frame, routes title/fullscreen updates through it, dispatches libdecor events during the frame loop, and tears it down safely without affecting the X11 path. Also add Wayland cursor-theme handling for the content surface so the app restores a normal arrow when re-entered from another application, reports a distro-correct warning when libdecor decorations cannot be provided, and exposes a content-side resize hotzone near the window edges and corners to make resizing practical even when the decoration backend's own hit targets are narrow. This change is Linux-only. macOS is unaffected because the code paths are guarded behind the Wayland/Linux build configuration and do not alter the shared Metal or Cocoa client behavior.
…text After merging upstream/master, resolve several issues introduced during conflict resolution: - Guard POSIX-only code in EDreamClient.cpp (#include <unistd.h>, LoginWithMagicLinkCode body) so Windows builds are not broken - Guard the Linux headless auth block in CElectricSheep::Startup() with #ifdef LINUX_GNU so Mac/Windows first-run startup is not short-circuited before the GUI auth flow can run - Restore null guards on g_Player().Renderer() and g_Player().Display() in StartupScreen constructor and CElectricSheep::Run() - Remove DrawSoftQuad override keyword from RendererVulkan (upstream removed the base class virtual in commit 1b4735d) - Fix Frame.h constructor assigning _width/_height to AVFrame fields - Fix duplicate ToggleFullscreen in DisplayOutput.h (bool vs void return) - Restore startup screen text rendering: draw "Connecting to infinidream.ai..." centered at top of screen via GetExtent() + DrawText Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@scottdraves - the Linux client has now been consolidated with upstream changes. When this is in I'll raise the AppImage work as a separate PR. |
|
awesome but i tried it on mac and it had problems, crashed right away. claude fixed that but then it wasn't responding to remote control commands. maybe i should try before the windows merge? |
Our earlier work replaced the upstream `if (USE_HW_ACCELERATION)` block with a `#ifdef LINUX_GNU` VAAPI block, which inadvertently deleted the Mac VideoToolbox initialisation. Without it, FFmpeg outputs software YUV frames. TextureFlatMetal::GetPixelBuffer() casts data[3] directly to CVPixelBufferRef; for software frames data[3] is null, causing an immediate crash the moment the first video starts playing. Once the app crashes the main loop stops running and ProcessCommandQueue() is never called, which is why remote-control commands also appeared broken. Fix: - Add a vt_get_format() callback (MAC-only, mirrors the existing vaapi_get_format for Linux) so the codec negotiates AV_PIX_FMT_VIDEOTOOLBOX rather than falling back to software YUV. - Restore VideoToolbox hw-device creation in ContentDecoder::Open() using av_hwdevice_ctx_create() (the correct one-step API, replacing the upstream's fragile alloc+init pattern) guarded with #elif defined(MAC). The Linux VAAPI path is untouched; Windows gets neither block and continues with software decoding as before. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Oops - fixed! |










Problem
When Metal replaced the OpenGL renderer on macOS,
RendererGL.cppwas never replaced for Linux. The Linux build had no rendering backend, no CMake build system, and accumulated compilation errors against modern toolchains (GCC, FFmpeg 6+, Boost 1.69+).Approach
Add a Vulkan backend for Linux with native Wayland support. Platform-specific code is isolated behind
#ifdef LINUX_GNU/#ifdef HAVE_WAYLANDguards; Mac paths are unchanged.What's included
Cross-platform fixes (safe on all platforms):
SmartPtr.h— guard_LIBCPP_INLINE_VISIBILITYfor libstdc++BlockingQueue.h— fixcondition_variable::wait()to take a lock object, not a raw mutexXTimer.h— remove<X11/Xlib.h>(itsNonemacro clashes withenum class TransitionType); makeTime()constFrameDisplay.h— guard<CoreVideo/CVPixelBuffer.h>inside#ifdef MACStringFormat.cpp— add missing<cstdarg>client.h— wrapSHAREDIRinstd::string()so it stores a path string in JSON, not a booleanContentDecoder.cpp— replace removedavcodec_closewithavcodec_free_context(FFmpeg 6+)PlaylistManager.h— add missing<condition_variable>/<mutex>TextureFlat.h— wrap FFmpeg headers inextern "C"EDreamClient.h— add missingSetQuota()declarationEDreamClient.cpp— fixstring_viewpassed to%s(UB on GCC, crashes at runtime)Linux platform additions:
LinuxBuild/CMakeLists.txt— finds Vulkan, X11, Boost, FFmpeg, OpenSSL, curl, libpng; compiles GLSL→SPIR-V via glslcPlatformUtils_Linux.cpp—/proc/self/exe, xdg-open, pthread naming, X11 blank cursor, OpenSSL MD5cpu_usage_linux.h—/proc/statreplacesglibtop;GetNumCores()viasysconfDisplayVulkan— X11 window +VK_KHR_xlib_surface; native Wayland viaVK_KHR_wayland_surface+ xdg-shell whenWAYLAND_DISPLAYis set; XScreensaver embed always uses X11; FIFO present mode for vsyncRendererVulkan— graphics pipeline, per-frame acquire/present, swapchain recreation onVK_ERROR_OUT_OF_DATE_KHR/VK_SUBOPTIMAL_KHR(required on Wayland for initial surface configuration)TextureFlatVulkan—VkImageupload fromCImageor decodedAVFrame(RGBA fast-path, dirty flag for re-bind after upload)shaders/quad.{vert,frag}— fullscreen blit with correct normalised coordinate handlingsocket.io-client-cpp/lib/linux/libsioclient{,_tls}.a— Linux ELF builds (Mach-O binaries untouched)INFINIDREAM_API_KEYenv var or stored setting, for headless/Linux environments without a browser-based sign-in flowVerified working
cd client_generic/LinuxBuild && cmake -B build -DCMAKE_BUILD_TYPE=Debug && cmake --build build && ./build/infinidreamArch Linux · kernel 6.19 · RTX 4090 · Vulkan 1.4.341 · GCC 15.1 · Boost 1.89 · FFmpeg 7.x
Mac safety
All changes to shared files add new
#elif/#elsebranches or fix genuine correctness bugs. Existing#ifdef MACblocks are byte-for-byte identical to upstream. The Mach-O socket.io binaries are not modified.