Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ const struct option *gamescope_options = (struct option[]){

// Steam Deck options
{ "mura-map", required_argument, nullptr, 0 },
// PipeWire options
{ "pipewire-source", required_argument, nullptr, 0 },
{ "pipewire-width", required_argument, nullptr, 0 },
{ "pipewire-height", required_argument, nullptr, 0 },

{} // keep last
};
Expand Down Expand Up @@ -209,6 +213,9 @@ const char usage[] =
" --framerate-limit Set a simple framerate limit. Used as a divisor of the refresh rate, rounds down eg 60 / 59 -> 60fps, 60 / 25 -> 30fps. Default: 0, disabled.\n"
" --mangoapp Launch with the mangoapp (mangohud) performance overlay enabled. You should use this instead of using mangohud on the game or gamescope.\n"
" --adaptive-sync Enable adaptive sync if available (variable rate refresh)\n"
" --pipewire-source Select PipeWire source: 'output' (default) or 'source' (unscaled source texture).\n"
" --pipewire-width Fixed width for PipeWire capture (overrides output width).\n"
" --pipewire-height Fixed height for PipeWire capture (overrides output height).\n"
"\n"
"Nested mode options:\n"
" -o, --nested-unfocused-refresh game refresh rate when unfocused\n"
Expand Down Expand Up @@ -680,6 +687,9 @@ static void UpdateCompatEnvVars()
int g_nPreferredOutputWidth = 0;
int g_nPreferredOutputHeight = 0;
bool g_bExposeWayland = false;
PipeWireSourceMode g_ePipewireSourceMode = PipeWireSourceMode::Output;
int g_nPipewireWidth = 0;
int g_nPipewireHeight = 0;
const char *g_sOutputName = nullptr;
bool g_bDebugLayers = false;
bool g_bForceDisableColorMgmt = false;
Expand Down Expand Up @@ -821,6 +831,19 @@ int main(int argc, char **argv)

}
}
} else if (strcmp(opt_name, "pipewire-source") == 0) {
if (strcmp(optarg, "source") == 0) {
g_ePipewireSourceMode = PipeWireSourceMode::Source;
} else if (strcmp(optarg, "output") == 0) {
g_ePipewireSourceMode = PipeWireSourceMode::Output;
} else {
fprintf( stderr, "gamescope: invalid pipewire source mode: %s\n", optarg );
return 1;
}
} else if (strcmp(opt_name, "pipewire-width") == 0) {
g_nPipewireWidth = atoi(optarg);
} else if (strcmp(opt_name, "pipewire-height") == 0) {
g_nPipewireHeight = atoi(optarg);
}
break;
case '?':
Expand Down
9 changes: 9 additions & 0 deletions src/main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,12 @@ extern int g_nXWaylandCount;
extern uint32_t g_preferVendorID;
extern uint32_t g_preferDeviceID;

enum class PipeWireSourceMode {
Output,
Source
};

extern PipeWireSourceMode g_ePipewireSourceMode;
extern int g_nPipewireWidth;
extern int g_nPipewireHeight;

12 changes: 11 additions & 1 deletion src/pipewire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static void destroy_buffer(struct pipewire_buffer *buffer) {
break; // nothing to do
default:
assert(false); // unreachable
}
}

// If out_buffer == buffer, then set it to nullptr.
// We don't care about the result.
Expand All @@ -71,6 +71,12 @@ void pipewire_destroy_buffer(struct pipewire_buffer *buffer)

static void calculate_capture_size()
{
if (g_nPipewireWidth > 0 && g_nPipewireHeight > 0) {
s_nCaptureWidth = g_nPipewireWidth;
s_nCaptureHeight = g_nPipewireHeight;
return;
}

s_nCaptureWidth = s_nOutputWidth;
s_nCaptureHeight = s_nOutputHeight;

Expand Down Expand Up @@ -280,6 +286,10 @@ static void dispatch_nudge(struct pipewire_state *state, int fd)
s_nOutputHeight = g_nOutputHeight;
calculate_capture_size();
}

if (g_nPipewireWidth > 0 && g_nPipewireHeight > 0) {
calculate_capture_size();
}
if (s_nCaptureWidth != state->video_info.size.width || s_nCaptureHeight != state->video_info.size.height) {
pwr_log.debugf("renegotiating stream params (size: %dx%d)", s_nCaptureWidth, s_nCaptureHeight);

Expand Down
40 changes: 28 additions & 12 deletions src/steamcompmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2023,6 +2023,7 @@ namespace PaintWindowFlag
static const uint32_t NoScale = 1u << 4;
static const uint32_t NoFilter = 1u << 5;
static const uint32_t CoverageMode = 1u << 6;
static const uint32_t PipeWire = 1u << 7;
}
using PaintWindowFlags = uint32_t;

Expand Down Expand Up @@ -2073,12 +2074,22 @@ paint_window_commit( const gamescope::Rc<commit_t> &lastCommit, steamcompmgr_win

layer->filter = ( flags & PaintWindowFlag::NoFilter ) ? GamescopeUpscaleFilter::LINEAR : g_upscaleFilter;

layer->tex = lastCommit->GetTexture( layer->filter, g_upscaleScaler, layer->colorspace );
// Use source texture for PipeWire when source mode is enabled
bool bUseSourceTexture = ( flags & PaintWindowFlag::PipeWire ) && ( g_ePipewireSourceMode == PipeWireSourceMode::Source );
layer->tex = bUseSourceTexture ? lastCommit->vulkanTex : lastCommit->GetTexture( layer->filter, g_upscaleScaler, layer->colorspace );

if ( flags & PaintWindowFlag::NoScale )
{
sourceWidth = currentOutputWidth;
sourceHeight = currentOutputHeight;
if ( flags & PaintWindowFlag::PipeWire && g_ePipewireSourceMode == PipeWireSourceMode::Source )
{
sourceWidth = layer->tex->width();
sourceHeight = layer->tex->height();
}
else
{
sourceWidth = currentOutputWidth;
sourceHeight = currentOutputHeight;
}
}
else
{
Expand Down Expand Up @@ -2108,22 +2119,27 @@ paint_window_commit( const gamescope::Rc<commit_t> &lastCommit, steamcompmgr_win
if ( fit )
{
// If we have an override window, try to fit it in as long as it won't make our scale go below 1.0.
sourceWidth = std::max<uint32_t>( sourceWidth, clamp<int>( fit->GetGeometry().nX + fit->GetGeometry().nWidth, 0, currentOutputWidth ) );
sourceHeight = std::max<uint32_t>( sourceHeight, clamp<int>( fit->GetGeometry().nY + fit->GetGeometry().nHeight, 0, currentOutputHeight ) );
uint32_t outputWidth = (flags & PaintWindowFlag::PipeWire && g_nPipewireWidth > 0) ? g_nPipewireWidth : currentOutputWidth;
uint32_t outputHeight = (flags & PaintWindowFlag::PipeWire && g_nPipewireHeight > 0) ? g_nPipewireHeight : currentOutputHeight;
sourceWidth = std::max<uint32_t>( sourceWidth, clamp<int>( fit->GetGeometry().nX + fit->GetGeometry().nWidth, 0, outputWidth ) );
sourceHeight = std::max<uint32_t>( sourceHeight, clamp<int>( fit->GetGeometry().nY + fit->GetGeometry().nHeight, 0, outputHeight ) );

baseWidth = std::max<uint32_t>( baseWidth, clamp<int>( fit->GetGeometry().nX + fit->GetGeometry().nWidth, 0, currentOutputWidth ) );
baseHeight = std::max<uint32_t>( baseHeight, clamp<int>( fit->GetGeometry().nY + fit->GetGeometry().nHeight, 0, currentOutputHeight ) );
baseWidth = std::max<uint32_t>( baseWidth, clamp<int>( fit->GetGeometry().nX + fit->GetGeometry().nWidth, 0, outputWidth ) );
baseHeight = std::max<uint32_t>( baseHeight, clamp<int>( fit->GetGeometry().nY + fit->GetGeometry().nHeight, 0, outputHeight ) );
}
}

bool offset = ( ( w->GetGeometry().nX || w->GetGeometry().nY ) && w != scaleW );

if (sourceWidth != (int32_t)currentOutputWidth || sourceHeight != (int32_t)currentOutputHeight || offset || globalScaleRatio != 1.0f)
uint32_t targetOutputWidth = (flags & PaintWindowFlag::PipeWire && g_nPipewireWidth > 0) ? g_nPipewireWidth : currentOutputWidth;
uint32_t targetOutputHeight = (flags & PaintWindowFlag::PipeWire && g_nPipewireHeight > 0) ? g_nPipewireHeight : currentOutputHeight;

if (sourceWidth != (int32_t)targetOutputWidth || sourceHeight != (int32_t)targetOutputHeight || offset || globalScaleRatio != 1.0f)
{
calc_scale_factor(currentScaleRatio_x, currentScaleRatio_y, sourceWidth, sourceHeight);

drawXOffset = ((int)currentOutputWidth - (int)sourceWidth * currentScaleRatio_x) / 2.0f;
drawYOffset = ((int)currentOutputHeight - (int)sourceHeight * currentScaleRatio_y) / 2.0f;
drawXOffset = ((int)targetOutputWidth - (int)sourceWidth * currentScaleRatio_x) / 2.0f;
drawYOffset = ((int)targetOutputHeight - (int)sourceHeight * currentScaleRatio_y) / 2.0f;

if ( w != scaleW )
{
Expand Down Expand Up @@ -2360,10 +2376,10 @@ static void paint_pipewire()
currentOutputHeight = uHeight;

// Paint the windows we have onto the Pipewire stream.
paint_window( pFocus->focusWindow, pFocus->focusWindow, &frameInfo, nullptr, 0, 1.0f, pFocus->overrideWindow );
paint_window( pFocus->focusWindow, pFocus->focusWindow, &frameInfo, nullptr, PaintWindowFlag::PipeWire, 1.0f, pFocus->overrideWindow );

if ( pFocus->overrideWindow && !pFocus->focusWindow->isSteamStreamingClient )
paint_window( pFocus->overrideWindow, pFocus->focusWindow, &frameInfo, nullptr, PaintWindowFlag::NoFilter, 1.0f, pFocus->overrideWindow );
paint_window( pFocus->overrideWindow, pFocus->focusWindow, &frameInfo, nullptr, PaintWindowFlag::NoFilter | PaintWindowFlag::PipeWire, 1.0f, pFocus->overrideWindow );

gamescope::Rc<CVulkanTexture> pRGBTexture = s_pPipewireBuffer->texture->isYcbcr()
? vulkan_acquire_screenshot_texture( uWidth, uHeight, false, DRM_FORMAT_XRGB2101010 )
Expand Down