/* * Copyright 2012-15 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD *
*/
new_stream = kmemdup(stream, sizeof(struct dc_stream_state), GFP_KERNEL); if (!new_stream) return NULL;
if (new_stream->sink)
dc_sink_retain(new_stream->sink);
dc_stream_assign_stream_id(new_stream);
/* If using dynamic encoder assignment, wait till stream committed to assign encoder. */ if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign &&
!new_stream->ctx->dc->config.unify_link_enc_assignment)
new_stream->link_enc = NULL;
kref_init(&new_stream->refcount);
return new_stream;
}
/** * dc_stream_get_status() - Get current stream status of the given stream state * @stream: The stream to get the stream status for. * * The given stream is expected to exist in dc->current_state. Otherwise, NULL * will be returned.
*/ struct dc_stream_status *dc_stream_get_status( struct dc_stream_state *stream)
{ struct dc *dc = stream->ctx->dc; return dc_state_get_stream_status(dc->current_state, stream);
}
void program_cursor_attributes( struct dc *dc, struct dc_stream_state *stream)
{ int i; struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL;
if (!stream) return;
res_ctx = &dc->current_state->res_ctx;
for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
if (pipe_ctx->stream != stream) continue;
if (!pipe_to_program) {
pipe_to_program = pipe_ctx;
dc->hwss.cursor_lock(dc, pipe_to_program, true); if (pipe_to_program->next_odm_pipe)
dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
}
dc->hwss.set_cursor_attribute(pipe_ctx); if (dc->ctx->dmub_srv)
dc_send_update_cursor_info_to_dmu(pipe_ctx, i); if (dc->hwss.set_cursor_sdr_white_level)
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
}
if (pipe_to_program) {
dc->hwss.cursor_lock(dc, pipe_to_program, false); if (pipe_to_program->next_odm_pipe)
dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
}
}
/* * dc_stream_check_cursor_attributes() - Check validitity of cursor attributes and surface address
*/ bool dc_stream_check_cursor_attributes( conststruct dc_stream_state *stream, struct dc_state *state, conststruct dc_cursor_attributes *attributes)
{ conststruct dc *dc;
unsignedint max_cursor_size;
if (NULL == stream) {
dm_error("DC: dc_stream is NULL!\n"); returnfalse;
} if (NULL == attributes) {
dm_error("DC: attributes is NULL!\n"); returnfalse;
}
if (attributes->address.quad_part == 0) {
dm_output_to_console("DC: Cursor address is 0!\n"); returnfalse;
}
dc = stream->ctx->dc;
/* SubVP is not compatible with HW cursor larger than what can fit in cursor SRAM. * Therefore, if cursor is greater than this, fallback to SW cursor.
*/ if (dc->debug.allow_sw_cursor_fallback && dc->res_pool->funcs->get_max_hw_cursor_size) {
max_cursor_size = dc->res_pool->funcs->get_max_hw_cursor_size(dc, state, stream);
max_cursor_size = max_cursor_size * max_cursor_size * 4;
program_cursor_position(dc, stream); /* re-enable idle optimizations if necessary */ if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
dc_allow_idle_optimizations(dc, true);
/* apply/update visual confirm */ if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR) { /* update software state */ int i;
for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
/* adjust visual confirm color for all pipes with current stream */ if (stream == pipe_ctx->stream) {
get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
if (stream == NULL) {
dm_error("DC: dc_stream is NULL!\n"); returnfalse;
}
if (dwb_pipe_inst >= MAX_DWB_PIPES) {
dm_error("DC: writeback pipe is invalid!\n"); returnfalse;
}
if (stream->num_wb_info > MAX_DWB_PIPES) {
dm_error("DC: num_wb_info is invalid!\n"); returnfalse;
}
dc_exit_ips_for_hw_access(dc);
if (dwb->funcs->set_fc_enable)
dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE);
returntrue;
}
/** * dc_stream_remove_writeback() - Disables writeback and removes writeback info. * @dc: Display core control structure. * @stream: Display core stream state. * @dwb_pipe_inst: Display writeback pipe. * * Return: returns true on success, false otherwise.
*/ bool dc_stream_remove_writeback(struct dc *dc, struct dc_stream_state *stream,
uint32_t dwb_pipe_inst)
{ unsignedint i, j; if (stream == NULL) {
dm_error("DC: dc_stream is NULL!\n"); returnfalse;
}
if (dwb_pipe_inst >= MAX_DWB_PIPES) {
dm_error("DC: writeback pipe is invalid!\n"); returnfalse;
}
if (stream->num_wb_info > MAX_DWB_PIPES) {
dm_error("DC: num_wb_info is invalid!\n"); returnfalse;
}
/* remove writeback info for disabled writeback pipes from stream */ for (i = 0, j = 0; i < stream->num_wb_info; i++) { if (stream->writeback_info[i].wb_enabled) {
if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst)
stream->writeback_info[i].wb_enabled = false;
/* trim the array */ if (j < i) {
memcpy(&stream->writeback_info[j], &stream->writeback_info[i], sizeof(struct dc_writeback_info));
j++;
}
}
}
stream->num_wb_info = j;
/* recalculate and apply DML parameters */ if (!dc->hwss.update_bandwidth(dc, dc->current_state)) {
dm_error("DC: update_bandwidth failed!\n"); returnfalse;
}
for (i = 0; i < MAX_PIPES; i++) { struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg;
if (res_ctx->pipe_ctx[i].stream != stream || !tg) continue;
return tg->funcs->get_frame_count(tg);
}
return 0;
}
bool dc_stream_send_dp_sdp(conststruct dc_stream_state *stream, const uint8_t *custom_sdp_message, unsignedint sdp_message_size)
{ int i; struct dc *dc; struct resource_context *res_ctx;
if (stream == NULL) {
dm_error("DC: dc_stream is NULL!\n"); returnfalse;
}
dc = stream->ctx->dc;
res_ctx = &dc->current_state->res_ctx;
dc_exit_ips_for_hw_access(dc);
for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
if (pipe_ctx->stream != stream) continue;
if (dc->hwss.send_immediate_sdp_message != NULL)
dc->hwss.send_immediate_sdp_message(pipe_ctx,
custom_sdp_message,
sdp_message_size); else
DC_LOG_WARNING("%s:send_immediate_sdp_message not implemented on this ASIC\n",
__func__);
bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream)
{ struct pipe_ctx *pipe = NULL; int i;
if (!dc->hwss.dmdata_status_done) returnfalse;
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe->stream == stream) break;
} /* Stream not found, by default we'll assume HUBP fetched dm data */ if (i == MAX_PIPES) returntrue;
/* * dc_stream_get_3dlut() * Requirements: * 1. Is stream already owns an RMCM instance, return it. * 2. If it doesn't and we don't need to allocate, return NULL. * 3. If there's a free RMCM instance, assign to stream and return it. * 4. If no free RMCM instances, return NULL.
*/
// see if one is allocated for this stream for (int i = 0; i < num_rmcm; i++) { if (dc->res_pool->rmcm_3dlut[i].isInUse &&
dc->res_pool->rmcm_3dlut[i].stream == stream) return &dc->res_pool->rmcm_3dlut[i];
}
//case: not found one, and dont need to allocate if (!allocate_one) return NULL;
//see if there is an unused 3dlut, allocate for (int i = 0; i < num_rmcm; i++) { if (!dc->res_pool->rmcm_3dlut[i].isInUse) {
dc->res_pool->rmcm_3dlut[i].isInUse = true;
dc->res_pool->rmcm_3dlut[i].stream = stream; return &dc->res_pool->rmcm_3dlut[i];
}
}
void dc_stream_init_rmcm_3dlut(struct dc *dc)
{ unsignedint num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
for (int i = 0; i < num_rmcm; i++) {
dc->res_pool->rmcm_3dlut[i].isInUse = false;
dc->res_pool->rmcm_3dlut[i].stream = NULL;
dc->res_pool->rmcm_3dlut[i].protection_bits = 0;
}
}
/* * Finds the greatest index in refresh_rate_hz that contains a value <= refresh
*/ staticint dc_stream_get_nearest_smallest_index(struct dc_stream_state *stream, int refresh)
{ for (int i = 0; i < (LUMINANCE_DATA_TABLE_SIZE - 1); ++i) { if ((stream->lumin_data.refresh_rate_hz[i] <= refresh) && (refresh < stream->lumin_data.refresh_rate_hz[i + 1])) { return i;
}
} return 9;
}
/* * Finds a corresponding brightness for a given refresh rate between 2 given indices, where index1 < index2
*/ staticint dc_stream_get_brightness_millinits_linear_interpolation (struct dc_stream_state *stream, int index1, int index2, int refresh_hz)
{ longlong slope = 0; if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) {
slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) /
(stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]);
}
int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2];
return (y_intercept + refresh_hz * slope);
}
/* * Finds a corresponding refresh rate for a given brightness between 2 given indices, where index1 < index2
*/ staticint dc_stream_get_refresh_hz_linear_interpolation (struct dc_stream_state *stream, int index1, int index2, int brightness_millinits)
{ longlong slope = 1; if (stream->lumin_data.refresh_rate_hz[index2] != stream->lumin_data.refresh_rate_hz[index1]) {
slope = (stream->lumin_data.luminance_millinits[index2] - stream->lumin_data.luminance_millinits[index1]) /
(stream->lumin_data.refresh_rate_hz[index2] - stream->lumin_data.refresh_rate_hz[index1]);
}
int y_intercept = stream->lumin_data.luminance_millinits[index2] - slope * stream->lumin_data.refresh_rate_hz[index2];
/* * Finds the current brightness in millinits given a refresh rate
*/ staticint dc_stream_get_brightness_millinits_from_refresh (struct dc_stream_state *stream, int refresh_hz)
{ int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, refresh_hz); int nearest_smallest_value = stream->lumin_data.refresh_rate_hz[nearest_smallest_index];
if (nearest_smallest_value == refresh_hz) return stream->lumin_data.luminance_millinits[nearest_smallest_index];
/* * Finds the lowest/highest refresh rate (depending on search_for_max_increase) * that can be achieved from starting_refresh_hz while staying * within flicker criteria
*/ staticint dc_stream_calculate_flickerless_refresh_rate(struct dc_stream_state *stream, int current_brightness, int starting_refresh_hz, bool is_gaming, bool search_for_max_increase)
{ int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, starting_refresh_hz);
int flicker_criteria_millinits = is_gaming ?
stream->lumin_data.flicker_criteria_milli_nits_GAMING :
stream->lumin_data.flicker_criteria_milli_nits_STATIC;
int safe_upper_bound = current_brightness + flicker_criteria_millinits; int safe_lower_bound = current_brightness - flicker_criteria_millinits; int lumin_millinits_temp = 0;
int offset = -1; if (search_for_max_increase) {
offset = 1;
}
/* * Increments up or down by 1 depending on search_for_max_increase
*/ for (int i = nearest_smallest_index; (i > 0 && !search_for_max_increase) || (i < (LUMINANCE_DATA_TABLE_SIZE - 1) && search_for_max_increase); i += offset) {
/* * Need the second input to be < third input for dc_stream_get_refresh_hz_linear_interpolation
*/ if (search_for_max_increase)
refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i, i + offset, target_brightness); else
refresh = dc_stream_get_refresh_hz_linear_interpolation(stream, i + offset, i, target_brightness);
if (refresh == stream->lumin_data.refresh_rate_hz[i + offset]) return stream->lumin_data.refresh_rate_hz[i + offset];
return refresh;
}
}
if (search_for_max_increase) return (int)div64_s64((longlong)stream->timing.pix_clk_100hz*100, stream->timing.v_total*(longlong)stream->timing.h_total); else return stream->lumin_data.refresh_rate_hz[0];
}
/* * Gets the max delta luminance within a specified refresh range
*/ staticint dc_stream_get_max_delta_lumin_millinits(struct dc_stream_state *stream, int hz1, int hz2, bool isGaming)
{ int lower_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz1); int higher_refresh_brightness = dc_stream_get_brightness_millinits_from_refresh (stream, hz2);
int min = lower_refresh_brightness; int max = higher_refresh_brightness;
/* * Static screen, therefore no need to scan through array
*/ if (!isGaming) { if (lower_refresh_brightness >= higher_refresh_brightness) { return lower_refresh_brightness - higher_refresh_brightness;
} return higher_refresh_brightness - lower_refresh_brightness;
}
min = MIN(lower_refresh_brightness, higher_refresh_brightness);
max = MAX(lower_refresh_brightness, higher_refresh_brightness);
int nearest_smallest_index = dc_stream_get_nearest_smallest_index(stream, hz1);
for (; nearest_smallest_index < (LUMINANCE_DATA_TABLE_SIZE - 1) &&
stream->lumin_data.refresh_rate_hz[nearest_smallest_index + 1] <= hz2 ; nearest_smallest_index++) {
min = MIN(min, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]);
max = MAX(max, stream->lumin_data.luminance_millinits[nearest_smallest_index + 1]);
}
return (max - min);
}
/* * Determines the max flickerless instant vtotal delta for a stream. * Determines vtotal increase/decrease based on the bool "increase"
*/ staticunsignedint dc_stream_get_max_flickerless_instant_vtotal_delta(struct dc_stream_state *stream, bool is_gaming, bool increase)
{ if (stream->timing.v_total * stream->timing.h_total == 0) return 0;
int current_refresh_hz = (int)div64_s64((longlong)stream->timing.pix_clk_100hz*100, stream->timing.v_total*(longlong)stream->timing.h_total);
int safe_refresh_hz = dc_stream_calculate_flickerless_refresh_rate(stream,
dc_stream_get_brightness_millinits_from_refresh(stream, current_refresh_hz),
current_refresh_hz,
is_gaming,
increase);
int safe_refresh_v_total = (int)div64_s64((longlong)stream->timing.pix_clk_100hz*100, safe_refresh_hz*(longlong)stream->timing.h_total);
/* * Finds the highest refresh rate that can be achieved * from starting_refresh_hz while staying within flicker criteria
*/ int dc_stream_calculate_max_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming)
{ if (!stream->lumin_data.is_valid) return 0;
int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz);
/* * Finds the lowest refresh rate that can be achieved * from starting_refresh_hz while staying within flicker criteria
*/ int dc_stream_calculate_min_flickerless_refresh_rate(struct dc_stream_state *stream, int starting_refresh_hz, bool is_gaming)
{ if (!stream->lumin_data.is_valid) return 0;
int current_brightness = dc_stream_get_brightness_millinits_from_refresh(stream, starting_refresh_hz);
/* * Determines if there will be a flicker when moving between 2 refresh rates
*/ bool dc_stream_is_refresh_rate_range_flickerless(struct dc_stream_state *stream, inthz1, int hz2, bool is_gaming)
{
/* * Assume that we wont flicker if there is invalid data
*/ if (!stream->lumin_data.is_valid) returnfalse;
int dl = dc_stream_get_max_delta_lumin_millinits(stream, hz1, hz2, is_gaming);
int flicker_criteria_millinits = (is_gaming) ?
stream->lumin_data.flicker_criteria_milli_nits_GAMING :
stream->lumin_data.flicker_criteria_milli_nits_STATIC;
return (dl <= flicker_criteria_millinits);
}
/* * Determines the max instant vtotal delta increase that can be applied without * flickering for a given stream
*/ unsignedint dc_stream_get_max_flickerless_instant_vtotal_decrease(struct dc_stream_state *stream, bool is_gaming)
{ if (!stream->lumin_data.is_valid) return 0;
/* * Determines the max instant vtotal delta decrease that can be applied without * flickering for a given stream
*/ unsignedint dc_stream_get_max_flickerless_instant_vtotal_increase(struct dc_stream_state *stream, bool is_gaming)
{ if (!stream->lumin_data.is_valid) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.