Allow the stereo modes drm_edid derives from a sink's HDMI VSDB on HDMI connectors, and drive them the way a 2D stream is driven: the source (compositor or media player) lays both views out in the frame itself - side by side, top and bottom, or the doubled frame-packing timing with the 45-line active space between the eyes - and the only 3D-specific output is the HDMI vendor infoframe that tells the sink how the frame is laid out.
Keep the DC timing at TIMING_3D_FORMAT_NONE for all of them. Any DC stereo timing format, including the SW_PACKED variants, makes the hardware treat the surface as two views: the pipe is split and both view addresses point at the same surface, so the whole frame ends up in each half of the output. The new vsif_3d_format stream field carries the layout to mod_build_hf_vsif_infopacket() instead, so the VSIF is right and stays right when the freesync code rebuilds it for ALLM. Frame packing needs the doubled CRTC timing; pass CRTC_STEREO_DOUBLE wherever amdgpu_dm recomputes the CRTC fields itself. Limit stereo_allowed to native HDMI connectors: on the DP-to-HDMI converter paths link validation rejects the 3D timings. Tested on a Radeon RX 7600 (DCN 3.2.1) driving a JVC DLA-RS4100 projector through an HDFury VRROOM, with Kodi rendering the packed frames: frame packing, top-and-bottom and side-by-side at 1920x1080p24, RGB 12 bpc, all engage the projector's 3D mode with correct per-eye geometry and eye assignment (checked with per-eye test patterns through shutter glasses). Signed-off-by: Adrian Betschart <[email protected]> --- .../display/amdgpu_dm/amdgpu_dm_connector.c | 41 +++++++++++++++++-- drivers/gpu/drm/amd/display/dc/dc_stream.h | 7 ++++ .../display/modules/info_packet/info_packet.c | 3 ++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c index 0e71ba498..7a2beb175 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c @@ -851,6 +851,25 @@ STATIC_IFN_KUNIT bool adjust_colour_depth_from_display_info( } EXPORT_IF_KUNIT(adjust_colour_depth_from_display_info); +/* + * 3D layout to announce in the HDMI vendor infoframe for a DRM 3D mode. The + * stream timing itself stays 2D (see fill_stream_properties_from_drm_display_mode). + */ +static enum dc_timing_3d_format amdgpu_dm_vsif_3d_format(unsigned int mode_flags) +{ + switch (mode_flags & DRM_MODE_FLAG_3D_MASK) { + case DRM_MODE_FLAG_3D_FRAME_PACKING: + return TIMING_3D_FORMAT_SW_FRAME_PACKING; + case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: + return TIMING_3D_FORMAT_TB_SW_PACKED; + case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: + case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: + return TIMING_3D_FORMAT_SBS_SW_PACKED; + default: + return TIMING_3D_FORMAT_NONE; + } +} + STATIC_IFN_KUNIT void fill_stream_properties_from_drm_display_mode( struct dc_stream_state *stream, const struct drm_display_mode *mode_in, @@ -887,7 +906,15 @@ STATIC_IFN_KUNIT void fill_stream_properties_from_drm_display_mode( */ timing_out->pixel_encoding = requested_encoding; + /* + * The source packs both views into the frame itself (side-by-side, + * top-and-bottom, or the doubled frame-packing timing), so the display + * core scans it out as a plain 2D stream and only the HDMI vendor + * infoframe tells the sink how the frame is laid out. Any DC stereo + * timing format would make the hardware treat the surface as two views. + */ timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; + stream->vsif_3d_format = amdgpu_dm_vsif_3d_format(mode_in->flags); timing_out->display_color_depth = amdgpu_dm_convert_color_depth_from_display_info( connector, (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420), @@ -1451,6 +1478,9 @@ create_stream_for_sink(struct drm_connector *connector, struct dc_sink *sink = NULL; drm_mode_init(&mode, drm_mode); + /* frame packing scans out both views plus the active space in one frame */ + if (mode.flags & DRM_MODE_FLAG_3D_FRAME_PACKING) + drm_mode_set_crtcinfo(&mode, CRTC_STEREO_DOUBLE); memset(&saved_mode, 0, sizeof(saved_mode)); if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { @@ -1530,7 +1560,9 @@ create_stream_for_sink(struct drm_connector *connector, } if (recalculate_timing) - drm_mode_set_crtcinfo(&saved_mode, 0); + drm_mode_set_crtcinfo(&saved_mode, + (saved_mode.flags & DRM_MODE_FLAG_3D_FRAME_PACKING) ? + CRTC_STEREO_DOUBLE : 0); /* * If scaling is enabled and refresh rate didn't change @@ -2449,7 +2481,9 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec if (!test_mode) goto fail; - drm_mode_set_crtcinfo(test_mode, 0); + drm_mode_set_crtcinfo(test_mode, + (test_mode->flags & DRM_MODE_FLAG_3D_FRAME_PACKING) ? + CRTC_STEREO_DOUBLE : 0); stream = amdgpu_dm_create_validate_stream_for_sink(connector, test_mode, to_dm_connector_state(connector->state), @@ -3143,7 +3177,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, aconnector->dc_link = link; aconnector->base.interlace_allowed = false; aconnector->base.doublescan_allowed = false; - aconnector->base.stereo_allowed = false; + /* HDMI 1.4 3D only; DP-to-HDMI converters reject the timings in link validation */ + aconnector->base.stereo_allowed = connector_type == DRM_MODE_CONNECTOR_HDMIA; aconnector->base.dpms = DRM_MODE_DPMS_OFF; aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ aconnector->audio_inst = -1; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 934ae381e..e6fd75b87 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -235,6 +235,13 @@ struct dc_stream_state { enum view_3d_format view_format; + /** + * @vsif_3d_format: 3D layout announced in the HDMI vendor infoframe when + * the source packs both views into the frame itself and the timing is + * therefore left at TIMING_3D_FORMAT_NONE. + */ + enum dc_timing_3d_format vsif_3d_format; + bool use_vsc_sdp_for_colorimetry; bool ignore_msa_timing_param; diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c index 32b697f46..13478b8bd 100644 --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c @@ -536,6 +536,9 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, format = stream->timing.timing_3d_format; if (stream->view_format == VIEW_3D_FORMAT_NONE) format = TIMING_3D_FORMAT_NONE; + /* a 2D scanout of a frame the source packed itself */ + if (format == TIMING_3D_FORMAT_NONE) + format = stream->vsif_3d_format; if (stream->timing.hdmi_vic != 0 && stream->timing.h_total >= 3840 -- 2.43.0
