diff --git a/src/drm.cpp b/src/drm.cpp index 6742899..8af5503 100644 --- a/src/drm.cpp +++ b/src/drm.cpp @@ -633,6 +633,9 @@ static bool refresh_state( drm_t *drm ) crtc->has_vrr_enabled = crtc->props.contains( "VRR_ENABLED" ); if (!crtc->has_vrr_enabled) drm_log.infof("CRTC %" PRIu32 " has no VRR_ENABLED support", crtc->id); + crtc->has_valve1_regamma_tf = crtc->props.contains( "VALVE1_CRTC_REGAMMA_TF" ); + if (!crtc->has_valve1_regamma_tf) + drm_log.infof("CRTC %" PRIu32 " has no VALVE1_CRTC_REGAMMA_TF support", crtc->id); crtc->lut3d_size = crtc->props.contains( "VALVE1_LUT3D_SIZE" ) ? uint32_t(crtc->initial_prop_values["VALVE1_LUT3D_SIZE"]) : 0; crtc->shaperlut_size = crtc->props.contains( "VALVE1_SHAPER_LUT_SIZE" ) ? uint32_t(crtc->initial_prop_values["VALVE1_SHAPER_LUT_SIZE"]) : 0; @@ -640,6 +643,8 @@ static bool refresh_state( drm_t *drm ) crtc->current.active = crtc->initial_prop_values["ACTIVE"]; if (crtc->has_vrr_enabled) drm->current.vrr_enabled = crtc->initial_prop_values["VRR_ENABLED"]; + if (crtc->has_valve1_regamma_tf) + drm->current.output_tf = (drm_valve1_transfer_function) crtc->initial_prop_values["VALVE1_CRTC_REGAMMA_TF"]; } for (size_t i = 0; i < drm->planes.size(); i++) { @@ -1142,6 +1147,8 @@ void finish_drm(struct drm_t *drm) add_crtc_property(req, &drm->crtcs[i], "VALVE1_SHAPER_LUT", 0); if ( drm->crtcs[i].has_vrr_enabled ) add_crtc_property(req, &drm->crtcs[i], "VRR_ENABLED", 0); + if ( drm->crtcs[i].has_valve1_regamma_tf ) + add_crtc_property(req, &drm->crtcs[i], "VALVE1_CRTC_REGAMMA_TF", 0); add_crtc_property(req, &drm->crtcs[i], "ACTIVE", 0); } for ( size_t i = 0; i < drm->planes.size(); i++ ) { @@ -1667,7 +1674,7 @@ struct LiftoffStateCacheEntry uint32_t crtcX, crtcY, crtcW, crtcH; drm_color_encoding colorEncoding; drm_color_range colorRange; - uint32_t transferFunction; + GamescopeAppTextureColorspace colorspace; } layerState[ k_nMaxLayers ]; bool operator == (const LiftoffStateCacheEntry& entry) const @@ -1694,7 +1701,7 @@ struct LiftoffStateCacheEntryKasher hash_combine(hash, k.layerState[i].crtcH); hash_combine(hash, k.layerState[i].colorEncoding); hash_combine(hash, k.layerState[i].colorRange); - hash_combine(hash, k.layerState[i].transferFunction); + hash_combine(hash, k.layerState[i].colorspace); } return hash; @@ -1783,11 +1790,11 @@ LiftoffStateCacheEntry FrameInfoToLiftoffStateCacheEntry( struct drm_t *drm, con { entry.layerState[i].colorEncoding = drm_get_color_encoding( g_ForcedNV12ColorSpace ); entry.layerState[i].colorRange = drm_get_color_range( g_ForcedNV12ColorSpace ); - entry.layerState[i].transferFunction = ColorSpaceToEOTFIndex( GAMESCOPE_APP_TEXTURE_COLORSPACE_SRGB ); + entry.layerState[i].colorspace = GAMESCOPE_APP_TEXTURE_COLORSPACE_SRGB; } else { - entry.layerState[i].transferFunction = ColorSpaceToEOTFIndex(frameInfo->layers[ i ].colorspace); + entry.layerState[i].colorspace = frameInfo->layers[ i ].colorspace; } } @@ -1860,9 +1867,11 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo liftoff_layer_set_property( drm->lo_layers[ i ], "COLOR_RANGE", entry.layerState[i].colorRange ); if ( drm_supports_color_mgmt( drm ) ) { + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", DRM_VALVE1_TRANSFER_FUNCTION_BT709 ); liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", 0 ); liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); } } else @@ -1871,9 +1880,11 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo liftoff_layer_unset_property( drm->lo_layers[ i ], "COLOR_RANGE" ); if ( drm_supports_color_mgmt( drm ) ) { - liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", drm->pending.shaperlut_id[ entry.layerState[i].transferFunction ] ); - liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); - liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", drm->pending.lut3d_id[ entry.layerState[i].transferFunction ] ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", convert_colorspace_to_valve1_drm( entry.layerState[i].colorspace ) ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", drm->pending.shaperlut_id[ ColorSpaceToEOTFIndex( entry.layerState[i].colorspace ) ] ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", convert_colorspace_to_valve1_drm( entry.layerState[i].colorspace ) ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", drm->pending.lut3d_id[ ColorSpaceToEOTFIndex( entry.layerState[i].colorspace ) ] ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", drm->pending.output_tf ); } } } @@ -1886,9 +1897,10 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo if ( drm_supports_color_mgmt( drm ) ) { + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", 0 ); - liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 ); + liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); } } } @@ -1969,6 +1981,17 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI } } + if ( drm_supports_color_mgmt( &g_DRM ) ) + { + drm->pending.output_tf = g_bOutputHDREnabled + ? DRM_VALVE1_TRANSFER_FUNCTION_PQ + : DRM_VALVE1_TRANSFER_FUNCTION_SRGB; + } + else + { + drm->pending.output_tf = DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT; + } + uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK; // We do internal refcounting with these events @@ -2059,6 +2082,12 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI if (ret < 0) return ret; } + if (crtc->has_valve1_regamma_tf) + { + int ret = add_crtc_property(drm->req, crtc, "VALVE1_CRTC_REGAMMA_TF", 0); + if (ret < 0) + return ret; + } ret = add_crtc_property(drm->req, crtc, "ACTIVE", 0); if (ret < 0) @@ -2106,6 +2135,13 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI return ret; } + if (drm->crtc->has_valve1_regamma_tf) + { + ret = add_crtc_property(drm->req, drm->crtc, "VALVE1_CRTC_REGAMMA_TF", drm->pending.output_tf); + if (ret < 0) + return ret; + } + ret = add_crtc_property(drm->req, drm->crtc, "ACTIVE", 1); if (ret < 0) return ret; @@ -2142,6 +2178,13 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI if (ret < 0) return ret; } + + if ( drm->crtc->has_valve1_regamma_tf && drm->pending.output_tf != drm->current.output_tf ) + { + int ret = add_crtc_property(drm->req, drm->crtc, "VALVE1_CRTC_REGAMMA_TF", drm->pending.output_tf ); + if (ret < 0) + return ret; + } } } diff --git a/src/drm.hpp b/src/drm.hpp index 6c0dbe4..0234b69 100644 --- a/src/drm.hpp +++ b/src/drm.hpp @@ -108,6 +108,7 @@ struct crtc { bool has_degamma_lut; bool has_ctm; bool has_vrr_enabled; + bool has_valve1_regamma_tf; uint32_t lut3d_size; uint32_t shaperlut_size; @@ -221,6 +222,7 @@ struct drm_t { uint32_t shaperlut_id[ ColorHelpers_EOTFCount ]; enum drm_screen_type screen_type = DRM_SCREEN_TYPE_INTERNAL; bool vrr_enabled = false; + drm_valve1_transfer_function output_tf = DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT; } current, pending; bool wants_vrr_enabled = false;