From: Joshua Ashton <joshua@froggi.es>
dc_acquire_release_mpc_3dlut_for_ctx initializes the bits required to
program 3DLUT in DC MPC hw block, applied in set_output_transfer_func().
Since acquire/release can fail, we should check resources availability
during atomic check considering the new context created. We dynamically
acquire 3D LUT resources when we actually use them, so we don't limit
ourselves with the stream count.
Co-developed-by: Melissa Wen <mwen@igalia.com>
Signed-off-by: Melissa Wen <mwen@igalia.com>
Signed-off-by: Joshua Ashton <joshua@froggi.es>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 +-
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 55 ++++++++++++++++++-
.../amd/display/dc/dcn301/dcn301_resource.c | 26 ++++++++-
4 files changed, 87 insertions(+), 4 deletions(-)
@@ -9380,7 +9380,12 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
*/
if (dm_new_crtc_state->base.color_mgmt_changed ||
drm_atomic_crtc_needs_modeset(new_crtc_state)) {
- ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state);
+ if (!dm_state) {
+ ret = dm_atomic_get_state(state, &dm_state);
+ if (ret)
+ goto fail;
+ }
+ ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state, dm_state->context);
if (ret)
goto fail;
}
@@ -904,7 +904,8 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
void amdgpu_dm_init_color_mod(void);
int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state);
-int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc);
+int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc,
+ struct dc_state *ctx);
int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
struct dc_plane_state *dc_plane_state);
@@ -332,6 +332,49 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream,
return ret;
}
+/* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC
+ * interface
+ * @dc: Display Core control structure
+ * @ctx: <add desc>
+ * @stream: DC stream state to set shaper LUT and 3D LUT
+ * @drm_shaper_lut: DRM CRTC (user) shaper LUT
+ * @drm_shaper_size: size of shaper LUT
+ * @drm_lut3d: DRM CRTC (user) 3D LUT
+ * @drm_lut3d_size: size of 3D LUT
+ *
+ * Returns:
+ * 0 on success.
+ */
+static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc,
+ struct dc_state *ctx,
+ struct dc_stream_state *stream,
+ const struct drm_color_lut *drm_shaper_lut,
+ uint32_t drm_shaper_size,
+ const struct drm_color_lut *drm_lut3d,
+ uint32_t drm_lut3d_size)
+{
+ struct dc_3dlut *lut3d_func;
+ struct dc_transfer_func *func_shaper;
+ bool acquire = drm_shaper_size && drm_lut3d_size;
+
+ lut3d_func = (struct dc_3dlut *)stream->lut3d_func;
+ func_shaper = (struct dc_transfer_func *)stream->func_shaper;
+
+ ASSERT((lut3d_func && func_shaper) || (!lut3d_func && !func_shaper));
+ if ((acquire && !lut3d_func && !func_shaper) ||
+ (!acquire && lut3d_func && func_shaper))
+ {
+ if (!dc_acquire_release_mpc_3dlut_for_ctx(dc, acquire, ctx, stream,
+ &lut3d_func, &func_shaper))
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ stream->lut3d_func = lut3d_func;
+ stream->func_shaper = func_shaper;
+
+ return 0;
+}
+
/**
* __set_input_tf - calculates the input transfer function based on expected
* input space.
@@ -402,6 +445,7 @@ int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)
/**
* amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream.
* @crtc: amdgpu_dm crtc state
+ * @ctx: <add desc>
*
* With no plane level color management properties we're free to use any
* of the HW blocks as long as the CRTC CTM always comes before the
@@ -421,7 +465,8 @@ int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)
* Returns:
* 0 on success. Error code if setup fails.
*/
-int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
+int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc,
+ struct dc_state *ctx)
{
struct dc_stream_state *stream = crtc->stream;
struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
@@ -480,6 +525,14 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
if (r)
return r;
} else {
+ r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream,
+ NULL, 0, NULL, 0);
+ if (r)
+ return r;
+ /* Note: OGAM is disabled if 3D LUT is successfully programmed.
+ * See params and set_output_gamma in
+ * dcn30_set_output_transfer_func()
+ */
regamma_size = has_regamma ? regamma_size : 0;
r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut,
regamma_size, has_rom);
@@ -1258,6 +1258,30 @@ static struct display_stream_compressor *dcn301_dsc_create(
return &dsc->base;
}
+static enum dc_status
+dcn301_remove_stream_from_ctx(struct dc *dc,
+ struct dc_state *new_ctx,
+ struct dc_stream_state *dc_stream)
+{
+ struct dc_3dlut *lut3d_func;
+ struct dc_transfer_func *func_shaper;
+
+ lut3d_func = (struct dc_3dlut *)dc_stream->lut3d_func;
+ func_shaper = (struct dc_transfer_func *)dc_stream->func_shaper;
+
+ ASSERT((lut3d_func && func_shaper) || (!lut3d_func && !func_shaper));
+ if (lut3d_func && func_shaper)
+ {
+ if (!dc_acquire_release_mpc_3dlut_for_ctx(dc, false, new_ctx, dc_stream,
+ &lut3d_func, &func_shaper))
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ dc_stream->lut3d_func = lut3d_func;
+ dc_stream->func_shaper = func_shaper;
+
+ return dcn20_remove_stream_from_ctx(dc, new_ctx, dc_stream);
+}
static void dcn301_destroy_resource_pool(struct resource_pool **pool)
{
@@ -1406,7 +1430,7 @@ static struct resource_funcs dcn301_res_pool_funcs = {
.acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer,
.add_stream_to_ctx = dcn30_add_stream_to_ctx,
.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
- .remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
+ .remove_stream_from_ctx = dcn301_remove_stream_from_ctx,
.populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context,
.set_mcif_arb_params = dcn30_set_mcif_arb_params,
.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,