Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useful display handling features #1105

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
17 changes: 17 additions & 0 deletions protocol/gamescope-control.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,22 @@
<arg name="path" type="string" summary="Path to written screenshot"></arg>
</event>

<enum name="display_rotation_flag" bitfield="true" since="2">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to set this to version 4? (since="4")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it doesn't really matter for enums.

<entry name="normal" value="1"/>
<entry name="left" value="2"/>
<entry name="right" value="3"/>
<entry name="upsidedown" value="4"/>
</enum>

<enum name="display_target_type" since="2">
<entry name="internal" value="1"/>
<entry name="external" value="2"/>
</enum>

<request name="rotate_display" since="2">
<arg name="orientation" type="uint" enum="display_rotation_flag" summary="Set the orientation of the display output."/>
<arg name="target_type" type="uint" enum="display_target_type" summary="Internal (1) or External (2) target type."/>
</request>

</interface>
</protocol>
124 changes: 79 additions & 45 deletions src/drm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ uint32_t g_nDRMFormat = DRM_FORMAT_INVALID;
uint32_t g_nDRMFormatOverlay = DRM_FORMAT_INVALID; // for partial composition, we may have more limited formats than base planes + alpha.
bool g_bRotated = false;
bool g_bDebugLayers = false;
enum drm_panel_type g_PanelType = PANEL_TYPE_EXTERNAL;
bool g_bPanelTypeFaked = false;
const char *g_sOutputName = nullptr;

#ifndef DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP
Expand All @@ -67,6 +69,8 @@ bool g_bSupportsAsyncFlips = false;

gamescope::GamescopeModeGeneration g_eGamescopeModeGeneration = gamescope::GAMESCOPE_MODE_GENERATE_CVT;
enum g_panel_orientation g_drmModeOrientation = PANEL_ORIENTATION_AUTO;
enum g_panel_external_orientation g_drmModeExternalOrientation = PANEL_EXTERNAL_ORIENTATION_AUTO;

std::atomic<uint64_t> g_drmEffectiveOrientation[gamescope::GAMESCOPE_SCREEN_TYPE_COUNT]{ {DRM_MODE_ROTATE_0}, {DRM_MODE_ROTATE_0} };

bool g_bForceDisableColorMgmt = false;
Expand Down Expand Up @@ -1595,60 +1599,62 @@ static uint64_t determine_drm_orientation(struct drm_t *drm, gamescope::CDRMConn
}

/* Handle the orientation of the display */
static void update_drm_effective_orientation(struct drm_t *drm, gamescope::CDRMConnector *pConnector, const drmModeModeInfo *mode)
static void update_drm_effective_orientation(struct drm_t *drm, gamescope::CDRMConnector *pConnector, const drmModeModeInfo *mode, bool fakedExternal)
{
gamescope::GamescopeScreenType eScreenType = pConnector->GetScreenType();

if ( eScreenType == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL )
{
switch ( g_drmModeOrientation )
{
case PANEL_ORIENTATION_0:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_0;
break;
case PANEL_ORIENTATION_90:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_90;
break;
case PANEL_ORIENTATION_180:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_180;
break;
case PANEL_ORIENTATION_270:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_270;
break;
case PANEL_ORIENTATION_AUTO:
g_drmEffectiveOrientation[eScreenType] = determine_drm_orientation( drm, pConnector, mode );
break;
}
}
if ( (eScreenType == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL) || (eScreenType == gamescope::GAMESCOPE_SCREEN_TYPE_EXTERNAL && fakedExternal))
{
// We are rotating an internal display or an internal display that is faked as external
switch (g_drmModeOrientation)
{
case PANEL_ORIENTATION_0:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_0;
break;
case PANEL_ORIENTATION_90:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_90;
break;
case PANEL_ORIENTATION_180:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_180;
break;
case PANEL_ORIENTATION_270:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_270;
break;
case PANEL_ORIENTATION_AUTO:
g_drmEffectiveOrientation[eScreenType] = determine_drm_orientation(drm, pConnector, mode);
break;
}
}
else if (eScreenType == gamescope::GAMESCOPE_SCREEN_TYPE_EXTERNAL)
{
// We are rotating a real external dislay
drm_log.infof("Rotating external display orientation");
switch (g_drmModeExternalOrientation)
{
default:
case PANEL_EXTERNAL_ORIENTATION_0:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_0;
break;
case PANEL_EXTERNAL_ORIENTATION_90:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_90;
break;
case PANEL_EXTERNAL_ORIENTATION_180:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_180;
break;
case PANEL_EXTERNAL_ORIENTATION_270:
g_drmEffectiveOrientation[eScreenType] = DRM_MODE_ROTATE_270;
break;
}
}
else
{
g_drmEffectiveOrientation[eScreenType] = determine_drm_orientation( drm, pConnector, mode );
}
}

static void update_drm_effective_orientations( struct drm_t *drm, const drmModeModeInfo *pMode )
static void update_drm_effective_orientations( struct drm_t *drm, const drmModeModeInfo *pMode, bool panel_flag )
{
gamescope::CDRMConnector *pInternalConnector = nullptr;
if ( drm->pConnector && drm->pConnector->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL )
pInternalConnector = drm->pConnector;

if ( !pInternalConnector )
{
for ( auto &iter : drm->connectors )
{
gamescope::CDRMConnector *pConnector = &iter.second;
if ( pConnector->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL )
{
pInternalConnector = pConnector;
// Find mode for internal connector instead.
pMode = find_mode(pInternalConnector->GetModeConnector(), 0, 0, 0);
break;
}
}
}

if ( pInternalConnector )
update_drm_effective_orientation( drm, pInternalConnector, pMode );
update_drm_effective_orientation( drm, drm->pConnector, pMode, panel_flag );
}

// Only used for NV12 buffers
Expand Down Expand Up @@ -2803,6 +2809,15 @@ gamescope::GamescopeScreenType drm_get_screen_type(struct drm_t *drm)
if ( !drm->pConnector )
return gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL;

if (g_PanelType == PANEL_TYPE_INTERNAL)
{
drm->pConnector->drm_force_panel_type(drm->pConnector->PANEL_TYPE_INTERNAL);
}

if (g_PanelType == PANEL_TYPE_EXTERNAL)
{
drm->pConnector->drm_force_panel_type(drm->pConnector->PANEL_TYPE_EXTERNAL);
}
return drm->pConnector->GetScreenType();
}

Expand Down Expand Up @@ -2882,6 +2897,25 @@ static void drm_unset_mode( struct drm_t *drm )
g_bRotated = false;
}

void drm_set_orientation( struct drm_t *drm, bool isRotated)
{
int width = g_nOutputWidth;
int height = g_nOutputHeight;
g_bRotated = isRotated;
if ( g_bRotated ) {
int tmp = width;
width = height;
height = tmp;
}

if (!drm->pConnector || !drm->pConnector->GetModeConnector())
return;

drmModeConnector *connector = drm->pConnector->GetModeConnector();
const drmModeModeInfo *mode = find_mode(connector, width, height, 0);
update_drm_effective_orientations(drm, mode, g_bPanelTypeFaked);
}

bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode )
{
if (!drm->pConnector || !drm->pConnector->GetModeConnector())
Expand All @@ -2900,7 +2934,7 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode )

g_nOutputRefresh = mode->vrefresh;

update_drm_effective_orientations(drm, mode);
update_drm_effective_orientations(drm, mode, g_bPanelTypeFaked);

switch ( g_drmEffectiveOrientation[screenType] )
{
Expand Down
47 changes: 44 additions & 3 deletions src/drm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,15 +344,37 @@ namespace gamescope
const HDRInfo &GetHDRInfo() const { return m_Mutable.HDR; }
std::span<const uint32_t> GetValidDynamicRefreshRates() const { return m_Mutable.ValidDynamicRefreshRates; }
GamescopeKnownDisplays GetKnownDisplayType() const { return m_Mutable.eKnownDisplay; }
enum panel_type {
PANEL_TYPE_INTERNAL,
PANEL_TYPE_EXTERNAL,
PANEL_TYPE_AUTO,
};

enum panel_type type = PANEL_TYPE_AUTO;

void drm_force_panel_type(panel_type target_type){
type = target_type;
}

GamescopeScreenType GetScreenType() const
{
if ( m_pConnector->connector_type == DRM_MODE_CONNECTOR_eDP ||
m_pConnector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
m_pConnector->connector_type == DRM_MODE_CONNECTOR_DSI )
if ( type == PANEL_TYPE_INTERNAL)
return GAMESCOPE_SCREEN_TYPE_INTERNAL;

if ( type == PANEL_TYPE_EXTERNAL)
return GAMESCOPE_SCREEN_TYPE_EXTERNAL;

if ( type == PANEL_TYPE_AUTO)
{
if ( m_pConnector->connector_type == DRM_MODE_CONNECTOR_eDP ||
m_pConnector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
m_pConnector->connector_type == DRM_MODE_CONNECTOR_DSI )
return GAMESCOPE_SCREEN_TYPE_INTERNAL;
}

return GAMESCOPE_SCREEN_TYPE_EXTERNAL;
}

bool IsVRRCapable() const
{
return this->GetProperties().vrr_capable && !!this->GetProperties().vrr_capable->GetCurrentValue();
Expand Down Expand Up @@ -521,6 +543,14 @@ enum g_panel_orientation {
PANEL_ORIENTATION_AUTO,
};

enum g_panel_external_orientation {
PANEL_EXTERNAL_ORIENTATION_0, /* NORMAL */
PANEL_EXTERNAL_ORIENTATION_270, /* RIGHT */
PANEL_EXTERNAL_ORIENTATION_90, /* LEFT */
PANEL_EXTERNAL_ORIENTATION_180, /* UPSIDE DOWN */
PANEL_EXTERNAL_ORIENTATION_AUTO,
};

enum drm_panel_orientation {
DRM_MODE_PANEL_ORIENTATION_UNKNOWN = -1,
DRM_MODE_PANEL_ORIENTATION_NORMAL = 0,
Expand All @@ -529,8 +559,18 @@ enum drm_panel_orientation {
DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
};

enum drm_panel_type{
PANEL_TYPE_INTERNAL,
PANEL_TYPE_EXTERNAL,
};

extern gamescope::GamescopeModeGeneration g_eGamescopeModeGeneration;
extern enum g_panel_orientation g_drmModeOrientation;
extern enum g_panel_external_orientation g_drmModeExternalOrientation;
extern enum drm_panel_type g_PanelType;

extern bool g_bPanelTypeFaked;


extern std::atomic<uint64_t> g_drmEffectiveOrientation[gamescope::GAMESCOPE_SCREEN_TYPE_COUNT]; // DRM_MODE_ROTATE_*

Expand All @@ -546,6 +586,7 @@ void drm_lock_fbid( struct drm_t *drm, uint32_t fbid );
void drm_unlock_fbid( struct drm_t *drm, uint32_t fbid );
void drm_drop_fbid( struct drm_t *drm, uint32_t fbid );
bool drm_set_connector( struct drm_t *drm, gamescope::CDRMConnector *conn );
void drm_set_orientation( struct drm_t *drm, bool isRotated );
bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode );
bool drm_set_refresh( struct drm_t *drm, int refresh );
bool drm_set_resolution( struct drm_t *drm, int width, int height );
Expand Down
37 changes: 37 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ const struct option *gamescope_options = (struct option[]){
{ "disable-xres", no_argument, nullptr, 'x' },
{ "fade-out-duration", required_argument, nullptr, 0 },
{ "force-orientation", required_argument, nullptr, 0 },
{ "force-external-orientation", required_argument, nullptr, 0 },
{ "force-panel-type", required_argument, nullptr, 0 },
{ "force-windows-fullscreen", no_argument, nullptr, 0 },

{ "disable-color-management", no_argument, nullptr, 0 },
Expand Down Expand Up @@ -169,6 +171,8 @@ const char usage[] =
" --xwayland-count create N xwayland servers\n"
" --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n"
" --force-orientation rotate the internal display (left, right, normal, upsidedown)\n"
" --force-external-orientation rotate the external display (left, right, normal, upsidedown)\n"
" --force-panel-type force Gamescope to treat the display as either internal or external\n"
" --force-windows-fullscreen force windows inside of gamescope to be the size of the nested display (fullscreen)\n"
" --cursor-scale-height if specified, sets a base output height to linearly scale the cursor against.\n"
" --hdr-enabled enable HDR output (needs Gamescope WSI layer enabled for support from clients)\n"
Expand Down Expand Up @@ -360,6 +364,19 @@ static gamescope::GamescopeModeGeneration parse_gamescope_mode_generation( const
}
}

static enum drm_panel_type force_panel_type(const char *str)
{
if (strcmp(str, "internal") == 0) {
return PANEL_TYPE_INTERNAL;
} else if (strcmp(str, "external") == 0) {
g_bPanelTypeFaked = true;
return PANEL_TYPE_EXTERNAL;
} else {
fprintf( stderr, "gamescope: invalid value for --force-panel-type\n" );
exit(1);
}
}

static enum g_panel_orientation force_orientation(const char *str)
{
if (strcmp(str, "normal") == 0) {
Expand All @@ -376,6 +393,22 @@ static enum g_panel_orientation force_orientation(const char *str)
}
}

static enum g_panel_external_orientation force_external_orientation(const char *str)
{
if (strcmp(str, "normal") == 0) {
return PANEL_EXTERNAL_ORIENTATION_0;
} else if (strcmp(str, "right") == 0) {
return PANEL_EXTERNAL_ORIENTATION_270;
} else if (strcmp(str, "left") == 0) {
return PANEL_EXTERNAL_ORIENTATION_90;
} else if (strcmp(str, "upsidedown") == 0) {
return PANEL_EXTERNAL_ORIENTATION_180;
} else {
fprintf( stderr, "gamescope: invalid value for --force-external-orientation\n" );
exit(1);
}
}

static enum GamescopeUpscaleScaler parse_upscaler_scaler(const char *str)
{
if (strcmp(str, "auto") == 0) {
Expand Down Expand Up @@ -619,6 +652,10 @@ int main(int argc, char **argv)
g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg );
} else if (strcmp(opt_name, "force-orientation") == 0) {
g_drmModeOrientation = force_orientation( optarg );
} else if (strcmp(opt_name, "force-external-orientation") == 0) {
g_drmModeExternalOrientation = force_external_orientation( optarg );
} else if (strcmp(opt_name, "force-panel-type") == 0) {
g_PanelType = force_panel_type( optarg );
} else if (strcmp(opt_name, "sharpness") == 0 ||
strcmp(opt_name, "fsr-sharpness") == 0) {
g_upscaleFilterSharpness = atoi( optarg );
Expand Down
Loading
Loading