Skip to content

Commit a92bbe9

Browse files
committed
GUI - add support for streaming the GUI via Spout on Windows
1 parent 7eafcef commit a92bbe9

27 files changed

Lines changed: 12301 additions & 7 deletions

‎app/CMakeLists.txt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ include(cmake/common.cmake)
6060
configure_file(${APP_ROOT}/cmake/config.h.cmake ${CMAKE_BINARY_DIR}/config.h)
6161

6262
add_subdirectory(external)
63+
# Vendored Spout2 — Windows-only sibling to external/Syphon-Framework.
64+
if(WIN32)
65+
add_subdirectory(external/Spout2)
66+
endif()
6367
add_subdirectory(api)
6468
add_subdirectory(api-tests)
6569
add_subdirectory(gui)
70+
71+
option(BUILD_SPOUT_SMOKETEST "Build tools/spout-receiver smoke-test (Windows)" OFF)
72+
if(WIN32 AND BUILD_SPOUT_SMOKETEST)
73+
add_subdirectory(tools/spout-receiver)
74+
endif()

‎app/external/Spout2/CMakeLists.txt‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Vendored Spout2 (DirectX 11 sender subset). Windows only.
2+
# Exposes the `spout_vendored` static target. See README.md for
3+
# upstream version and local patches.
4+
5+
if(NOT WIN32)
6+
return()
7+
endif()
8+
9+
set(SPOUTSDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/SPOUTSDK)
10+
11+
add_library(spout_vendored STATIC
12+
${SPOUTSDK_DIR}/SpoutGL/SpoutCopy.cpp
13+
${SPOUTSDK_DIR}/SpoutGL/SpoutDirectX.cpp
14+
${SPOUTSDK_DIR}/SpoutGL/SpoutFrameCount.cpp
15+
${SPOUTSDK_DIR}/SpoutGL/SpoutSenderNames.cpp
16+
${SPOUTSDK_DIR}/SpoutGL/SpoutSharedMemory.cpp
17+
${SPOUTSDK_DIR}/SpoutGL/SpoutUtils.cpp
18+
${SPOUTSDK_DIR}/SpoutDirectX/SpoutDX/SpoutDX.cpp
19+
)
20+
21+
# PUBLIC — both paths are needed:
22+
# - SPOUTSDK/ resolves SpoutDX.h's `#include "SpoutGL\X.h"`
23+
# - SPOUTSDK/SpoutDirectX/SpoutDX resolves `#include "SpoutDX.h"`
24+
target_include_directories(spout_vendored PUBLIC
25+
${SPOUTSDK_DIR}
26+
${SPOUTSDK_DIR}/SpoutDirectX/SpoutDX
27+
)
28+
29+
# SPOUT_BUILD_DLL selects static-archive symbol decoration. Without it,
30+
# some Spout headers default to __declspec(dllimport) depending on
31+
# include order.
32+
target_compile_definitions(spout_vendored PRIVATE SPOUT_BUILD_DLL)
33+
34+
# PUBLIC — system libs flow up to consumers.
35+
target_link_libraries(spout_vendored PUBLIC
36+
d3d11 dxgi dxguid
37+
ole32 oleaut32 uuid shlwapi advapi32 Version
38+
)
39+
40+
target_compile_features(spout_vendored PUBLIC cxx_std_17)
41+
42+
if(MSVC)
43+
target_compile_options(spout_vendored PRIVATE
44+
/W3 /D_CRT_SECURE_NO_WARNINGS)
45+
endif()

‎app/external/Spout2/LICENSE‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
BSD 2-Clause License
2+
3+
Copyright (c) 2020, Lynn Jarvis
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

‎app/external/Spout2/README.md‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Spout2 (vendored subset)
2+
3+
This directory contains a vendored, minimal subset of [Spout2](https://github.com/leadedge/Spout2)
4+
— the server-side DirectX 11 sender used by Sonic Pi's *Publish Window via Spout* feature
5+
on Windows. Counterpart to the macOS `Syphon-Framework/` vendor.
6+
7+
## Upstream
8+
9+
- Repo: <https://github.com/leadedge/Spout2>
10+
- Version: **2.007.010**
11+
- Source commit: `62362774c96547d63b502d7efd5cfbf138eb7570`
12+
- License: BSD-2-Clause (`LICENSE`)
13+
14+
## Subset
15+
16+
Only the SpoutDX (DirectX 11 sender) path is shipped. The OpenGL helpers, GL-based
17+
Spout/SpoutSender/SpoutReceiver wrappers, demos, examples and the SpoutPanel /
18+
SpoutSettings tools are deliberately omitted.
19+
20+
```
21+
SPOUTSDK/
22+
├── SpoutGL/ ← runtime backing (despite the "GL" dir name,
23+
│ ├── SpoutCommon.h these files are the DX subset's deps)
24+
│ ├── SpoutCopy.{h,cpp}
25+
│ ├── SpoutDirectX.{h,cpp}
26+
│ ├── SpoutFrameCount.{h,cpp}
27+
│ ├── SpoutSenderNames.{h,cpp}
28+
│ ├── SpoutSharedMemory.{h,cpp}
29+
│ └── SpoutUtils.{h,cpp}
30+
└── SpoutDirectX/SpoutDX/
31+
└── SpoutDX.{h,cpp} ← the public facade we consume
32+
```
33+
34+
## Local modifications
35+
36+
Three patches applied directly to the source — they do **not** exist as separate
37+
`.patch` files in this tree because the vendored copy is checked in already-patched.
38+
39+
### 1. fix-include-path
40+
41+
`SpoutDirectX/SpoutDX/SpoutDX.h` uses quote-form includes like
42+
`#include "SpoutGL\SpoutCommon.h"`. Upstream's CMake builds `SpoutDX` as a
43+
separate target with its own private include path that lets `..\..\SpoutGL\X.h`
44+
resolve. In our in-tree build the headers come from this directory's structure
45+
directly, so the relative paths were normalised to single-segment form.
46+
47+
### 2. fix-dx-keyed
48+
49+
`spoutDX::spoutDX()` ctor: explicitly initialises `m_bKeyed = false` so the
50+
keyed-mutex code path is deterministic without depending on whatever a default
51+
caller may have set.
52+
53+
### 3. fix-arm64 (Sonic Pi specific)
54+
55+
Spout's `SpoutCopy.{h,cpp}` uses SSE2/SSSE3 intrinsics (`<emmintrin.h>`,
56+
`<tmmintrin.h>`, `__m128i`, `_mm_*`) for fast pixel copies, plus 3 `__movsd`
57+
calls in `SpoutCopy.cpp` and 3 in `SpoutSenderNames.cpp` for the 280-byte
58+
shared-sender-info struct. None of those compile for MSVC on ARM64.
59+
60+
Modifications:
61+
62+
- SSE includes guarded with `#if defined(_M_IX86) || defined(_M_AMD64)`,
63+
defining `SPOUT_HAS_SSE` to 1 / 0.
64+
- `spoutCopy::memcpy_sse2`, `rgba_bgra_sse2`, `rgba_bgra_sse3` and
65+
`rgb_to_bgrx_sse` function bodies wrapped in `#if SPOUT_HAS_SSE`, with
66+
scalar `memcpy` (or no-op) fallbacks on ARM64. The call sites are already
67+
runtime-guarded by `m_bSSE2 / m_bSSSE3` flags which stay `false` on ARM64
68+
because `CheckSSE()`'s `__cpuid` calls are also gated out.
69+
- Six `__movsd(dst, src, n)` calls replaced with `memcpy(dst, src, n*4)`.
70+
Semantically equivalent. On x64 / x86 modern MSVC `memcpy` is heavily
71+
optimised (often emits the same `rep movs` instruction internally).
72+
73+
On x86 / x64 the patches are inert — `SPOUT_HAS_SSE` is 1, all SSE bodies
74+
compile as upstream, runtime SSE-detection works, behaviour is identical.
75+
76+
The `__movsd` -> `memcpy` swap is unconditional but the perf difference is
77+
sub-microsecond on a 280-byte struct copied once per sender event — not on
78+
any hot path.
79+
80+
## Updating
81+
82+
To pull a new upstream Spout2 release:
83+
84+
1. Download `https://github.com/leadedge/Spout2/archive/<commit>.tar.gz`
85+
2. Diff against this tree to see what's drifted in the subset above.
86+
3. Re-apply the three modifications above (the `fix-arm64` one is the only
87+
non-trivial diff).
88+
4. Bump the version + commit references in this README.
89+
90+
Long term: upstreaming the ARM64 changes to `leadedge/Spout2` would eliminate
91+
the third patch entirely. The mods follow the same `_M_IX86 || _M_AMD64`
92+
pattern Spout already uses internally in some places, so a PR should be
93+
mechanical.

0 commit comments

Comments
 (0)