mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2026-01-26 05:42:15 +00:00
drm/amd/display: Refactor recout calculation with a more generic formula
[Why] Current recout calculation has a few assumptions and implementation for MPO + ODM combine calculation is very specific. The equation has too many cases without enough comments to document the detail. [How] The change remove the following assumptions: 1. When MPO is enabled, we only allow ODM Combine 2:1 2. ODM Combine always has even segment width. 3. Secondary MPO plane's pipe_ctx copies pre_odm_pipe from its top pipe. The change applies a generic formula with more details in comment to document this solution so it is eaiser to learn and debug later. Reviewed-by: Dmytro Laktyushkin <dmytro.laktyushkin@amd.com> Acked-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Wenjing Liu <wenjing.liu@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
6917b0b711
commit
0f3b9542c9
@ -69,9 +69,10 @@
|
||||
#include "../dcn32/dcn32_resource.h"
|
||||
#include "../dcn321/dcn321_resource.h"
|
||||
|
||||
#define VISUAL_CONFIRM_RECT_HEIGHT_DEFAULT 3
|
||||
#define VISUAL_CONFIRM_RECT_HEIGHT_MIN 1
|
||||
#define VISUAL_CONFIRM_RECT_HEIGHT_MAX 10
|
||||
#define VISUAL_CONFIRM_BASE_DEFAULT 3
|
||||
#define VISUAL_CONFIRM_BASE_MIN 1
|
||||
#define VISUAL_CONFIRM_BASE_MAX 10
|
||||
#define VISUAL_CONFIRM_DPP_OFFSET 3
|
||||
|
||||
#define DC_LOGGER_INIT(logger)
|
||||
|
||||
@ -746,7 +747,12 @@ int get_num_mpc_splits(struct pipe_ctx *pipe)
|
||||
int get_num_odm_splits(struct pipe_ctx *pipe)
|
||||
{
|
||||
int odm_split_count = 0;
|
||||
struct pipe_ctx *next_pipe = pipe->next_odm_pipe;
|
||||
struct pipe_ctx *next_pipe = NULL;
|
||||
|
||||
while (pipe->top_pipe)
|
||||
pipe = pipe->top_pipe;
|
||||
|
||||
next_pipe = pipe->next_odm_pipe;
|
||||
while (next_pipe) {
|
||||
odm_split_count++;
|
||||
next_pipe = next_pipe->next_odm_pipe;
|
||||
@ -759,32 +765,35 @@ int get_num_odm_splits(struct pipe_ctx *pipe)
|
||||
return odm_split_count;
|
||||
}
|
||||
|
||||
static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *split_count, int *split_idx)
|
||||
static int get_odm_split_index(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
*split_count = get_num_odm_splits(pipe_ctx);
|
||||
*split_idx = 0;
|
||||
if (*split_count == 0) {
|
||||
/*Check for mpc split*/
|
||||
struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
|
||||
struct pipe_ctx *split_pipe = NULL;
|
||||
int index = 0;
|
||||
|
||||
*split_count = get_num_mpc_splits(pipe_ctx);
|
||||
while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
|
||||
(*split_idx)++;
|
||||
split_pipe = split_pipe->top_pipe;
|
||||
}
|
||||
while (pipe_ctx->top_pipe)
|
||||
pipe_ctx = pipe_ctx->top_pipe;
|
||||
|
||||
/* MPO window on right side of ODM split */
|
||||
if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe)
|
||||
(*split_idx)++;
|
||||
} else {
|
||||
/*Get odm split index*/
|
||||
struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe;
|
||||
split_pipe = pipe_ctx->prev_odm_pipe;
|
||||
|
||||
while (split_pipe) {
|
||||
(*split_idx)++;
|
||||
split_pipe = split_pipe->prev_odm_pipe;
|
||||
}
|
||||
while (split_pipe) {
|
||||
index++;
|
||||
split_pipe = split_pipe->prev_odm_pipe;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int get_mpc_split_index(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
struct pipe_ctx *split_pipe = pipe_ctx->top_pipe;
|
||||
int index = 0;
|
||||
|
||||
while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) {
|
||||
index++;
|
||||
split_pipe = split_pipe->top_pipe;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -806,101 +815,357 @@ static void calculate_viewport_size(struct pipe_ctx *pipe_ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static struct rect intersect_rec(const struct rect *r0, const struct rect *r1)
|
||||
{
|
||||
struct rect rec;
|
||||
int r0_x_end = r0->x + r0->width;
|
||||
int r1_x_end = r1->x + r1->width;
|
||||
int r0_y_end = r0->y + r0->height;
|
||||
int r1_y_end = r1->y + r1->height;
|
||||
|
||||
rec.x = r0->x > r1->x ? r0->x : r1->x;
|
||||
rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;
|
||||
rec.y = r0->y > r1->y ? r0->y : r1->y;
|
||||
rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;
|
||||
|
||||
/* in case that there is no intersection */
|
||||
if (rec.width < 0 || rec.height < 0)
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
static struct rect shift_rec(const struct rect *rec_in, int x, int y)
|
||||
{
|
||||
struct rect rec_out = *rec_in;
|
||||
|
||||
rec_out.x += x;
|
||||
rec_out.y += y;
|
||||
|
||||
return rec_out;
|
||||
}
|
||||
|
||||
static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
const struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
int odm_slice_count = get_num_odm_splits(pipe_ctx) + 1;
|
||||
int odm_slice_idx = get_odm_split_index(pipe_ctx);
|
||||
bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
|
||||
int h_active = stream->timing.h_addressable +
|
||||
stream->timing.h_border_left +
|
||||
stream->timing.h_border_right;
|
||||
int odm_slice_width = h_active / odm_slice_count;
|
||||
struct rect odm_rec;
|
||||
|
||||
odm_rec.x = odm_slice_width * odm_slice_idx;
|
||||
odm_rec.width = is_last_odm_slice ?
|
||||
/* last slice width is the reminder of h_active */
|
||||
h_active - odm_slice_width * (odm_slice_count - 1) :
|
||||
/* odm slice width is the floor of h_active / count */
|
||||
odm_slice_width;
|
||||
odm_rec.y = 0;
|
||||
odm_rec.height = stream->timing.v_addressable +
|
||||
stream->timing.v_border_bottom +
|
||||
stream->timing.v_border_top;
|
||||
|
||||
return odm_rec;
|
||||
}
|
||||
|
||||
static struct rect calculate_plane_rec_in_timing_active(
|
||||
struct pipe_ctx *pipe_ctx,
|
||||
const struct rect *rec_in)
|
||||
{
|
||||
/*
|
||||
* The following diagram shows an example where we map a 1920x1200
|
||||
* desktop to a 2560x1440 timing with a plane rect in the middle
|
||||
* of the screen. To map a plane rect from Stream Source to Timing
|
||||
* Active space, we first multiply stream scaling ratios (i.e 2304/1920
|
||||
* horizontal and 1440/1200 vertical) to the plane's x and y, then
|
||||
* we add stream destination offsets (i.e 128 horizontal, 0 vertical).
|
||||
* This will give us a plane rect's position in Timing Active. However
|
||||
* we have to remove the fractional. The rule is that we find left/right
|
||||
* and top/bottom positions and round the value to the adjacent integer.
|
||||
*
|
||||
* Stream Source Space
|
||||
* ------------
|
||||
* __________________________________________________
|
||||
* |Stream Source (1920 x 1200) ^ |
|
||||
* | y |
|
||||
* | <------- w --------|> |
|
||||
* | __________________V |
|
||||
* |<-- x -->|Plane//////////////| ^ |
|
||||
* | |(pre scale)////////| | |
|
||||
* | |///////////////////| | |
|
||||
* | |///////////////////| h |
|
||||
* | |///////////////////| | |
|
||||
* | |///////////////////| | |
|
||||
* | |///////////////////| V |
|
||||
* | |
|
||||
* | |
|
||||
* |__________________________________________________|
|
||||
*
|
||||
*
|
||||
* Timing Active Space
|
||||
* ---------------------------------
|
||||
*
|
||||
* Timing Active (2560 x 1440)
|
||||
* __________________________________________________
|
||||
* |*****| Stteam Destination (2304 x 1440) |*****|
|
||||
* |*****| |*****|
|
||||
* |<128>| |*****|
|
||||
* |*****| __________________ |*****|
|
||||
* |*****| |Plane/////////////| |*****|
|
||||
* |*****| |(post scale)//////| |*****|
|
||||
* |*****| |//////////////////| |*****|
|
||||
* |*****| |//////////////////| |*****|
|
||||
* |*****| |//////////////////| |*****|
|
||||
* |*****| |//////////////////| |*****|
|
||||
* |*****| |*****|
|
||||
* |*****| |*****|
|
||||
* |*****| |*****|
|
||||
* |*****|______________________________________|*****|
|
||||
*
|
||||
* So the resulting formulas are shown below:
|
||||
*
|
||||
* recout_x = 128 + round(plane_x * 2304 / 1920)
|
||||
* recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x
|
||||
* recout_y = 0 + round(plane_y * 1440 / 1280)
|
||||
* recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y
|
||||
*
|
||||
* NOTE: fixed point division is not error free. To reduce errors
|
||||
* introduced by fixed point division, we divide only after
|
||||
* multiplication is complete.
|
||||
*/
|
||||
const struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct rect rec_out = {0};
|
||||
struct fixed31_32 temp;
|
||||
|
||||
temp = dc_fixpt_from_fraction(rec_in->x * stream->dst.width,
|
||||
stream->src.width);
|
||||
rec_out.x = stream->dst.x + dc_fixpt_round(temp);
|
||||
|
||||
temp = dc_fixpt_from_fraction(
|
||||
(rec_in->x + rec_in->width) * stream->dst.width,
|
||||
stream->src.width);
|
||||
rec_out.width = stream->dst.x + dc_fixpt_round(temp) - rec_out.x;
|
||||
|
||||
temp = dc_fixpt_from_fraction(rec_in->y * stream->dst.height,
|
||||
stream->src.height);
|
||||
rec_out.y = stream->dst.y + dc_fixpt_round(temp);
|
||||
|
||||
temp = dc_fixpt_from_fraction(
|
||||
(rec_in->y + rec_in->height) * stream->dst.height,
|
||||
stream->src.height);
|
||||
rec_out.height = stream->dst.y + dc_fixpt_round(temp) - rec_out.y;
|
||||
|
||||
return rec_out;
|
||||
}
|
||||
|
||||
static struct rect calculate_mpc_slice_in_timing_active(
|
||||
struct pipe_ctx *pipe_ctx,
|
||||
struct rect *plane_clip_rec)
|
||||
{
|
||||
const struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
int mpc_slice_count = get_num_mpc_splits(pipe_ctx) + 1;
|
||||
int mpc_slice_idx = get_mpc_split_index(pipe_ctx);
|
||||
int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
|
||||
struct rect mpc_rec;
|
||||
|
||||
mpc_rec.width = plane_clip_rec->width / mpc_slice_count;
|
||||
mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
|
||||
mpc_rec.height = plane_clip_rec->height;
|
||||
mpc_rec.y = plane_clip_rec->y;
|
||||
ASSERT(mpc_slice_count == 1 ||
|
||||
stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE ||
|
||||
mpc_rec.width % 2 == 0);
|
||||
|
||||
/* extra pixels in the division remainder need to go to pipes after
|
||||
* the extra pixel index minus one(epimo) defined here as:
|
||||
*/
|
||||
if (mpc_slice_idx > epimo) {
|
||||
mpc_rec.x += mpc_slice_idx - epimo - 1;
|
||||
mpc_rec.width += 1;
|
||||
}
|
||||
|
||||
if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
|
||||
ASSERT(mpc_rec.height % 2 == 0);
|
||||
mpc_rec.height /= 2;
|
||||
}
|
||||
return mpc_rec;
|
||||
}
|
||||
|
||||
static void adjust_recout_for_visual_confirm(struct rect *recout,
|
||||
struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
struct dc *dc = pipe_ctx->stream->ctx->dc;
|
||||
int dpp_offset, base_offset;
|
||||
|
||||
if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE)
|
||||
return;
|
||||
|
||||
dpp_offset = pipe_ctx->plane_res.dpp->inst * VISUAL_CONFIRM_DPP_OFFSET;
|
||||
|
||||
if ((dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_BASE_MIN) &&
|
||||
dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_BASE_MAX)
|
||||
base_offset = dc->debug.visual_confirm_rect_height;
|
||||
else
|
||||
base_offset = VISUAL_CONFIRM_BASE_DEFAULT;
|
||||
|
||||
recout->height -= base_offset;
|
||||
recout->height -= dpp_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function maps a plane clip from Stream Source Space to ODM Slice Space
|
||||
* and calculates the rec of the overlapping area of MPC slice of the plane
|
||||
* clip, ODM slice associated with the pipe context and stream destination rec.
|
||||
*/
|
||||
static void calculate_recout(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
|
||||
const struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
|
||||
struct rect surf_clip = plane_state->clip_rect;
|
||||
bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM;
|
||||
int split_count, split_idx;
|
||||
struct dpp *dpp = pipe_ctx->plane_res.dpp;
|
||||
unsigned short visual_confirm_rect_height = VISUAL_CONFIRM_RECT_HEIGHT_DEFAULT;
|
||||
|
||||
calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
|
||||
if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
|
||||
split_idx = 0;
|
||||
|
||||
/*
|
||||
* Only the leftmost ODM pipe should be offset by a nonzero distance
|
||||
* A plane clip represents the desired plane size and position in Stream
|
||||
* Source Space. Stream Source is the destination where all planes are
|
||||
* blended (i.e. positioned, scaled and overlaid). It is a canvas where
|
||||
* all planes associated with the current stream are drawn together.
|
||||
* After Stream Source is completed, we will further scale and
|
||||
* reposition the entire canvas of the stream source to Stream
|
||||
* Destination in Timing Active Space. This could be due to display
|
||||
* overscan adjustment where we will need to rescale and reposition all
|
||||
* the planes so they can fit into a TV with overscan or downscale
|
||||
* upscale features such as GPU scaling or VSR.
|
||||
*
|
||||
* This two step blending is a virtual procedure in software. In
|
||||
* hardware there is no such thing as Stream Source. all planes are
|
||||
* blended once in Timing Active Space. Software virtualizes a Stream
|
||||
* Source space to decouple the math complicity so scaling param
|
||||
* calculation focuses on one step at a time.
|
||||
*
|
||||
* In the following two diagrams, user applied 10% overscan adjustment
|
||||
* so the Stream Source needs to be scaled down a little before mapping
|
||||
* to Timing Active Space. As a result the Plane Clip is also scaled
|
||||
* down by the same ratio, Plane Clip position (i.e. x and y) with
|
||||
* respect to Stream Source is also scaled down. To map it in Timing
|
||||
* Active Space additional x and y offsets from Stream Destination are
|
||||
* added to Plane Clip as well.
|
||||
*
|
||||
* Stream Source Space
|
||||
* ------------
|
||||
* __________________________________________________
|
||||
* |Stream Source (3840 x 2160) ^ |
|
||||
* | y |
|
||||
* | | |
|
||||
* | __________________V |
|
||||
* |<-- x -->|Plane Clip/////////| |
|
||||
* | |(pre scale)////////| |
|
||||
* | |///////////////////| |
|
||||
* | |///////////////////| |
|
||||
* | |///////////////////| |
|
||||
* | |///////////////////| |
|
||||
* | |///////////////////| |
|
||||
* | |
|
||||
* | |
|
||||
* |__________________________________________________|
|
||||
*
|
||||
*
|
||||
* Timing Active Space (3840 x 2160)
|
||||
* ---------------------------------
|
||||
*
|
||||
* Timing Active
|
||||
* __________________________________________________
|
||||
* | y_____________________________________________ |
|
||||
* |x |Stream Destination (3456 x 1944) | |
|
||||
* | | | |
|
||||
* | | __________________ | |
|
||||
* | | |Plane Clip////////| | |
|
||||
* | | |(post scale)//////| | |
|
||||
* | | |//////////////////| | |
|
||||
* | | |//////////////////| | |
|
||||
* | | |//////////////////| | |
|
||||
* | | |//////////////////| | |
|
||||
* | | | |
|
||||
* | | | |
|
||||
* | |____________________________________________| |
|
||||
* |__________________________________________________|
|
||||
*
|
||||
*
|
||||
* In Timing Active Space a plane clip could be further sliced into
|
||||
* pieces called MPC slices. Each Pipe Context is responsible for
|
||||
* processing only one MPC slice so the plane processing workload can be
|
||||
* distributed to multiple DPP Pipes. MPC slices could be blended
|
||||
* together to a single ODM slice. Each ODM slice is responsible for
|
||||
* processing a portion of Timing Active divided horizontally so the
|
||||
* output pixel processing workload can be distributed to multiple OPP
|
||||
* pipes. All ODM slices are mapped together in ODM block so all MPC
|
||||
* slices belong to different ODM slices could be pieced together to
|
||||
* form a single image in Timing Active. MPC slices must belong to
|
||||
* single ODM slice. If an MPC slice goes across ODM slice boundary, it
|
||||
* needs to be divided into two MPC slices one for each ODM slice.
|
||||
*
|
||||
* In the following diagram the output pixel processing workload is
|
||||
* divided horizontally into two ODM slices one for each OPP blend tree.
|
||||
* OPP0 blend tree is responsible for processing left half of Timing
|
||||
* Active, while OPP2 blend tree is responsible for processing right
|
||||
* half.
|
||||
*
|
||||
* The plane has two MPC slices. However since the right MPC slice goes
|
||||
* across ODM boundary, two DPP pipes are needed one for each OPP blend
|
||||
* tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).
|
||||
*
|
||||
* Assuming that we have a Pipe Context associated with OPP0 and DPP1
|
||||
* working on processing the plane in the diagram. We want to know the
|
||||
* width and height of the shaded rectangle and its relative position
|
||||
* with respect to the ODM slice0. This is called the recout of the pipe
|
||||
* context.
|
||||
*
|
||||
* Planes can be at arbitrary size and position and there could be an
|
||||
* arbitrary number of MPC and ODM slices. The algorithm needs to take
|
||||
* all scenarios into account.
|
||||
*
|
||||
* Timing Active Space (3840 x 2160)
|
||||
* ---------------------------------
|
||||
*
|
||||
* Timing Active
|
||||
* __________________________________________________
|
||||
* |OPP0(ODM slice0)^ |OPP2(ODM slice1) |
|
||||
* | y | |
|
||||
* | | <- w -> |
|
||||
* | _____V________|____ |
|
||||
* | |DPP0 ^ |DPP1 |DPP2| |
|
||||
* |<------ x |-----|->|/////| | |
|
||||
* | | | |/////| | |
|
||||
* | | h |/////| | |
|
||||
* | | | |/////| | |
|
||||
* | |_____V__|/////|____| |
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* |_________________________|________________________|
|
||||
*
|
||||
*
|
||||
*/
|
||||
if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) {
|
||||
/* MPO window on right side of ODM split */
|
||||
data->recout.x = stream->dst.x + (surf_clip.x - stream->src.x - stream->src.width/2) *
|
||||
stream->dst.width / stream->src.width;
|
||||
} else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) {
|
||||
data->recout.x = stream->dst.x;
|
||||
if (stream->src.x < surf_clip.x)
|
||||
data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width
|
||||
/ stream->src.width;
|
||||
} else
|
||||
data->recout.x = 0;
|
||||
struct rect plane_clip;
|
||||
struct rect mpc_slice_of_plane_clip;
|
||||
struct rect odm_slice;
|
||||
struct rect overlapping_area;
|
||||
|
||||
if (stream->src.x > surf_clip.x)
|
||||
surf_clip.width -= stream->src.x - surf_clip.x;
|
||||
data->recout.width = surf_clip.width * stream->dst.width / stream->src.width;
|
||||
if (data->recout.width + data->recout.x > stream->dst.x + stream->dst.width)
|
||||
data->recout.width = stream->dst.x + stream->dst.width - data->recout.x;
|
||||
plane_clip = calculate_plane_rec_in_timing_active(pipe_ctx,
|
||||
&pipe_ctx->plane_state->clip_rect);
|
||||
/* guard plane clip from drawing beyond stream dst here */
|
||||
plane_clip = intersect_rec(&plane_clip,
|
||||
&pipe_ctx->stream->dst);
|
||||
mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(
|
||||
pipe_ctx, &plane_clip);
|
||||
odm_slice = calculate_odm_slice_in_timing_active(pipe_ctx);
|
||||
overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice);
|
||||
/* shift the overlapping area so it is with respect to current ODM
|
||||
* slice's position
|
||||
*/
|
||||
pipe_ctx->plane_res.scl_data.recout = shift_rec(
|
||||
&overlapping_area,
|
||||
-odm_slice.x, -odm_slice.y);
|
||||
|
||||
data->recout.y = stream->dst.y;
|
||||
if (stream->src.y < surf_clip.y)
|
||||
data->recout.y += (surf_clip.y - stream->src.y) * stream->dst.height
|
||||
/ stream->src.height;
|
||||
else if (stream->src.y > surf_clip.y)
|
||||
surf_clip.height -= stream->src.y - surf_clip.y;
|
||||
|
||||
data->recout.height = surf_clip.height * stream->dst.height / stream->src.height;
|
||||
if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height)
|
||||
data->recout.height = stream->dst.y + stream->dst.height - data->recout.y;
|
||||
|
||||
/* Handle h & v split */
|
||||
if (split_tb) {
|
||||
ASSERT(data->recout.height % 2 == 0);
|
||||
data->recout.height /= 2;
|
||||
} else if (split_count) {
|
||||
if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) {
|
||||
/* extra pixels in the division remainder need to go to pipes after
|
||||
* the extra pixel index minus one(epimo) defined here as:
|
||||
*/
|
||||
int epimo = split_count - data->recout.width % (split_count + 1);
|
||||
|
||||
data->recout.x += (data->recout.width / (split_count + 1)) * split_idx;
|
||||
if (split_idx > epimo)
|
||||
data->recout.x += split_idx - epimo - 1;
|
||||
ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0);
|
||||
data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0);
|
||||
} else {
|
||||
/* odm */
|
||||
if (split_idx == split_count) {
|
||||
/* rightmost pipe is the remainder recout */
|
||||
data->recout.width -= data->h_active * split_count - data->recout.x;
|
||||
|
||||
/* ODM combine cases with MPO we can get negative widths */
|
||||
if (data->recout.width < 0)
|
||||
data->recout.width = 0;
|
||||
|
||||
data->recout.x = 0;
|
||||
} else
|
||||
data->recout.width = data->h_active - data->recout.x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check bounds to ensure the VC bar height was set to a sane value */
|
||||
if (dpp != NULL) {
|
||||
if ((dpp->ctx->dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_RECT_HEIGHT_MIN) &&
|
||||
(dpp->ctx->dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_RECT_HEIGHT_MAX)) {
|
||||
visual_confirm_rect_height = dpp->ctx->dc->debug.visual_confirm_rect_height;
|
||||
}
|
||||
|
||||
if (dpp->ctx->dc->debug.visual_confirm !=
|
||||
VISUAL_CONFIRM_DISABLE)
|
||||
data->recout.height = data->recout.height -
|
||||
2 * ((pipe_ctx->prev_odm_pipe ||
|
||||
(pipe_ctx->top_pipe &&
|
||||
pipe_ctx->top_pipe->plane_state ==
|
||||
pipe_ctx->plane_state)) +
|
||||
visual_confirm_rect_height);
|
||||
}
|
||||
adjust_recout_for_visual_confirm(&pipe_ctx->plane_res.scl_data.recout,
|
||||
pipe_ctx);
|
||||
}
|
||||
|
||||
static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
|
||||
@ -1022,34 +1287,25 @@ static void calculate_init_and_vp(
|
||||
static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
|
||||
const struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
|
||||
struct rect src = plane_state->src_rect;
|
||||
struct rect recout_dst_in_active_timing;
|
||||
struct rect recout_clip_in_active_timing;
|
||||
struct rect recout_clip_in_recout_dst;
|
||||
struct rect odm_slice = calculate_odm_slice_in_timing_active(pipe_ctx);
|
||||
int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
|
||||
|| data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
|
||||
int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y;
|
||||
bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
|
||||
|
||||
calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx);
|
||||
/*
|
||||
* recout full is what the recout would have been if we didnt clip
|
||||
* the source plane at all. We only care about left(ro_lb) and top(ro_tb)
|
||||
* offsets of recout within recout full because those are the directions
|
||||
* we scan from and therefore the only ones that affect inits.
|
||||
*/
|
||||
recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x)
|
||||
* stream->dst.width / stream->src.width;
|
||||
recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y)
|
||||
* stream->dst.height / stream->src.height;
|
||||
if (pipe_ctx->prev_odm_pipe && split_idx)
|
||||
ro_lb = data->h_active * split_idx - recout_full_x;
|
||||
else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe)
|
||||
ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x;
|
||||
else
|
||||
ro_lb = data->recout.x - recout_full_x;
|
||||
ro_tb = data->recout.y - recout_full_y;
|
||||
ASSERT(ro_lb >= 0 && ro_tb >= 0);
|
||||
|
||||
recout_clip_in_active_timing = shift_rec(
|
||||
&data->recout, odm_slice.x, odm_slice.y);
|
||||
recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(
|
||||
pipe_ctx, &plane_state->dst_rect);
|
||||
recout_clip_in_recout_dst = shift_rec(&recout_clip_in_active_timing,
|
||||
-recout_dst_in_active_timing.x,
|
||||
-recout_dst_in_active_timing.y);
|
||||
ASSERT(recout_clip_in_recout_dst.x >= 0 &&
|
||||
recout_clip_in_recout_dst.y >= 0);
|
||||
/*
|
||||
* Work in recout rotation since that requires less transformations
|
||||
*/
|
||||
@ -1067,7 +1323,7 @@ static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
|
||||
|
||||
calculate_init_and_vp(
|
||||
flip_horz_scan_dir,
|
||||
ro_lb,
|
||||
recout_clip_in_recout_dst.x,
|
||||
data->recout.width,
|
||||
src.width,
|
||||
data->taps.h_taps,
|
||||
@ -1077,7 +1333,7 @@ static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
|
||||
&data->viewport.width);
|
||||
calculate_init_and_vp(
|
||||
flip_horz_scan_dir,
|
||||
ro_lb,
|
||||
recout_clip_in_recout_dst.x,
|
||||
data->recout.width,
|
||||
src.width / vpc_div,
|
||||
data->taps.h_taps_c,
|
||||
@ -1087,7 +1343,7 @@ static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
|
||||
&data->viewport_c.width);
|
||||
calculate_init_and_vp(
|
||||
flip_vert_scan_dir,
|
||||
ro_tb,
|
||||
recout_clip_in_recout_dst.y,
|
||||
data->recout.height,
|
||||
src.height,
|
||||
data->taps.v_taps,
|
||||
@ -1097,7 +1353,7 @@ static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
|
||||
&data->viewport.height);
|
||||
calculate_init_and_vp(
|
||||
flip_vert_scan_dir,
|
||||
ro_tb,
|
||||
recout_clip_in_recout_dst.y,
|
||||
data->recout.height,
|
||||
src.height / vpc_div,
|
||||
data->taps.v_taps_c,
|
||||
@ -1122,6 +1378,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
|
||||
struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
|
||||
const struct rect odm_slice_rec = calculate_odm_slice_in_timing_active(pipe_ctx);
|
||||
bool res = false;
|
||||
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
|
||||
|
||||
@ -1146,30 +1403,9 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
|
||||
pipe_ctx->stream->dst.y += timing->v_border_top;
|
||||
|
||||
/* Calculate H and V active size */
|
||||
pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable +
|
||||
timing->h_border_left + timing->h_border_right;
|
||||
pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable +
|
||||
timing->v_border_top + timing->v_border_bottom;
|
||||
if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) {
|
||||
pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1;
|
||||
pipe_ctx->plane_res.scl_data.h_active = odm_slice_rec.width;
|
||||
pipe_ctx->plane_res.scl_data.v_active = odm_slice_rec.height;
|
||||
|
||||
DC_LOG_SCALER("%s pipe %d: next_odm_pipe:%d prev_odm_pipe:%d\n",
|
||||
__func__,
|
||||
pipe_ctx->pipe_idx,
|
||||
pipe_ctx->next_odm_pipe ? pipe_ctx->next_odm_pipe->pipe_idx : -1,
|
||||
pipe_ctx->prev_odm_pipe ? pipe_ctx->prev_odm_pipe->pipe_idx : -1);
|
||||
} /* ODM + windows MPO, where window is on either right or left ODM half */
|
||||
else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) {
|
||||
|
||||
pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1;
|
||||
|
||||
DC_LOG_SCALER("%s ODM + windows MPO: pipe:%d top_pipe:%d top_pipe->next_odm_pipe:%d top_pipe->prev_odm_pipe:%d\n",
|
||||
__func__,
|
||||
pipe_ctx->pipe_idx,
|
||||
pipe_ctx->top_pipe->pipe_idx,
|
||||
pipe_ctx->top_pipe->next_odm_pipe ? pipe_ctx->top_pipe->next_odm_pipe->pipe_idx : -1,
|
||||
pipe_ctx->top_pipe->prev_odm_pipe ? pipe_ctx->top_pipe->prev_odm_pipe->pipe_idx : -1);
|
||||
}
|
||||
/* depends on h_active */
|
||||
calculate_recout(pipe_ctx);
|
||||
/* depends on pixel format */
|
||||
|
||||
@ -854,8 +854,8 @@ bool dcn21_fast_validate_bw(struct dc *dc,
|
||||
/* We only support full screen mpo with ODM */
|
||||
if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled
|
||||
&& pipe->plane_state && mpo_pipe
|
||||
&& memcmp(&mpo_pipe->plane_res.scl_data.recout,
|
||||
&pipe->plane_res.scl_data.recout,
|
||||
&& memcmp(&mpo_pipe->plane_state->clip_rect,
|
||||
&pipe->stream->src,
|
||||
sizeof(struct rect)) != 0) {
|
||||
ASSERT(mpo_pipe->plane_state != pipe->plane_state);
|
||||
goto validate_fail;
|
||||
|
||||
@ -1705,8 +1705,8 @@ noinline bool dcn30_internal_validate_bw(
|
||||
/* We only support full screen mpo with ODM */
|
||||
if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled
|
||||
&& pipe->plane_state && mpo_pipe
|
||||
&& memcmp(&mpo_pipe->plane_res.scl_data.recout,
|
||||
&pipe->plane_res.scl_data.recout,
|
||||
&& memcmp(&mpo_pipe->plane_state->clip_rect,
|
||||
&pipe->stream->src,
|
||||
sizeof(struct rect)) != 0) {
|
||||
ASSERT(mpo_pipe->plane_state != pipe->plane_state);
|
||||
goto validate_fail;
|
||||
|
||||
@ -1717,8 +1717,8 @@ bool dcn32_internal_validate_bw(struct dc *dc,
|
||||
if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled
|
||||
&& !dc->config.enable_windowed_mpo_odm
|
||||
&& pipe->plane_state && mpo_pipe
|
||||
&& memcmp(&mpo_pipe->plane_res.scl_data.recout,
|
||||
&pipe->plane_res.scl_data.recout,
|
||||
&& memcmp(&mpo_pipe->plane_state->clip_rect,
|
||||
&pipe->stream->src,
|
||||
sizeof(struct rect)) != 0) {
|
||||
ASSERT(mpo_pipe->plane_state != pipe->plane_state);
|
||||
goto validate_fail;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user