switch (tiling_caps) { case INTEL_PLANE_CAP_TILING_Y: return I915_TILING_Y; case INTEL_PLANE_CAP_TILING_X: return I915_TILING_X; case INTEL_PLANE_CAP_TILING_4: case INTEL_PLANE_CAP_TILING_Yf: case INTEL_PLANE_CAP_TILING_NONE: return I915_TILING_NONE; default:
MISSING_CASE(tiling_caps); return I915_TILING_NONE;
}
}
/** * intel_fb_get_format_info: Get a modifier specific format information * @pixel_format: pixel format * @modifier: modifier * * Returns: * Returns the format information for @pixel_format specific to @modifier, * or %NULL if the modifier doesn't override the format.
*/ conststruct drm_format_info *
intel_fb_get_format_info(u32 pixel_format, u64 modifier)
{ conststruct intel_modifier_desc *md = lookup_modifier_or_null(modifier);
/** * intel_fb_is_tiled_modifier: Check if a modifier is a tiled modifier type * @modifier: Modifier to check * * Returns: * Returns %true if @modifier is a tiled modifier.
*/ bool intel_fb_is_tiled_modifier(u64 modifier)
{ return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
INTEL_PLANE_CAP_TILING_MASK);
}
/** * intel_fb_is_ccs_modifier: Check if a modifier is a CCS modifier type * @modifier: Modifier to check * * Returns: * Returns %true if @modifier is a render, render with color clear or * media compression modifier.
*/ bool intel_fb_is_ccs_modifier(u64 modifier)
{ return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
INTEL_PLANE_CAP_CCS_MASK);
}
/** * intel_fb_is_rc_ccs_cc_modifier: Check if a modifier is an RC CCS CC modifier type * @modifier: Modifier to check * * Returns: * Returns %true if @modifier is a render with color clear modifier.
*/ bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier)
{ return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
INTEL_PLANE_CAP_CCS_RC_CC);
}
/** * intel_fb_is_mc_ccs_modifier: Check if a modifier is an MC CCS modifier type * @modifier: Modifier to check * * Returns: * Returns %true if @modifier is a media compression modifier.
*/ bool intel_fb_is_mc_ccs_modifier(u64 modifier)
{ return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
INTEL_PLANE_CAP_CCS_MC);
}
/** * intel_fb_is_tile4_modifier: Check if a modifier is a tile4 modifier type * @modifier: Modifier to check * * Returns: * Returns %true if @modifier is a tile4 modifier.
*/ bool intel_fb_is_tile4_modifier(u64 modifier)
{ return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
INTEL_PLANE_CAP_TILING_4);
}
if (!IS_DISPLAY_VER(display, md->display_ver.from, md->display_ver.until)) returnfalse;
if (!plane_caps_contain_all(plane_caps, md->plane_caps)) returnfalse;
/* * Separate AuxCCS and Flat CCS modifiers to be run only on platforms * where supported.
*/ if (intel_fb_is_ccs_modifier(md->modifier) &&
HAS_FLAT_CCS(i915) != !md->ccs.packed_aux_planes) returnfalse;
/** * intel_fb_plane_get_modifiers: Get the modifiers for the given platform and plane capabilities * @display: display instance * @plane_caps: capabilities for the plane the modifiers are queried for * * Returns: * Returns the list of modifiers allowed by the @display platform and @plane_caps. * The caller must free the returned buffer.
*/
u64 *intel_fb_plane_get_modifiers(struct intel_display *display,
u8 plane_caps)
{
u64 *list, *p; int count = 1; /* +1 for invalid modifier terminator */ int i;
for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) { if (plane_has_modifier(display, plane_caps, &intel_modifiers[i]))
count++;
}
list = kmalloc_array(count, sizeof(*list), GFP_KERNEL); if (drm_WARN_ON(display->drm, !list)) return NULL;
p = list; for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) { if (plane_has_modifier(display, plane_caps, &intel_modifiers[i]))
*p++ = intel_modifiers[i].modifier;
}
*p++ = DRM_FORMAT_MOD_INVALID;
return list;
}
/** * intel_fb_plane_supports_modifier: Determine if a modifier is supported by the given plane * @plane: Plane to check the modifier support for * @modifier: The modifier to check the support for * * Returns: * %true if the @modifier is supported on @plane.
*/ bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier)
{ int i;
for (i = 0; i < plane->base.modifier_count; i++) if (plane->base.modifiers[i] == modifier) returntrue;
/** * intel_format_info_is_yuv_semiplanar: Check if the given format is YUV semiplanar * @info: format to check * @modifier: modifier used with the format * * Returns: * %true if @info / @modifier is YUV semiplanar.
*/ bool intel_format_info_is_yuv_semiplanar(conststruct drm_format_info *info,
u64 modifier)
{ return format_is_yuv_semiplanar(lookup_modifier(modifier), info);
}
/** * intel_fb_is_ccs_aux_plane: Check if a framebuffer color plane is a CCS AUX plane * @fb: Framebuffer * @color_plane: color plane index to check * * Returns: * Returns %true if @fb's color plane at index @color_plane is a CCS AUX plane.
*/ bool intel_fb_is_ccs_aux_plane(conststruct drm_framebuffer *fb, int color_plane)
{ conststruct intel_modifier_desc *md = lookup_modifier(fb->modifier);
/** * intel_fb_is_gen12_ccs_aux_plane: Check if a framebuffer color plane is a GEN12 CCS AUX plane * @fb: Framebuffer * @color_plane: color plane index to check * * Returns: * Returns %true if @fb's color plane at index @color_plane is a GEN12 CCS AUX plane.
*/ staticbool intel_fb_is_gen12_ccs_aux_plane(conststruct drm_framebuffer *fb, int color_plane)
{ conststruct intel_modifier_desc *md = lookup_modifier(fb->modifier);
/** * intel_fb_rc_ccs_cc_plane: Get the CCS CC color plane index for a framebuffer * @fb: Framebuffer * * Returns: * Returns the index of the color clear plane for @fb, or -1 if @fb is not a * framebuffer using a render compression/color clear modifier.
*/ int intel_fb_rc_ccs_cc_plane(conststruct drm_framebuffer *fb)
{ conststruct intel_modifier_desc *md = lookup_modifier(fb->modifier);
switch (fb->modifier) { case DRM_FORMAT_MOD_LINEAR: return intel_tile_size(display); case I915_FORMAT_MOD_X_TILED: if (DISPLAY_VER(display) == 2) return 128; else return 512; case I915_FORMAT_MOD_4_TILED_BMG_CCS: case I915_FORMAT_MOD_4_TILED_LNL_CCS: case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS: case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC: case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS: case I915_FORMAT_MOD_4_TILED: /* * Each 4K tile consists of 64B(8*8) subtiles, with * same shape as Y Tile(i.e 4*16B OWords)
*/ return 128; case I915_FORMAT_MOD_Y_TILED_CCS: if (intel_fb_is_ccs_aux_plane(fb, color_plane)) return 128;
fallthrough; case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS: case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC: case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS: case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: if (intel_fb_is_ccs_aux_plane(fb, color_plane) ||
is_gen12_ccs_cc_plane(fb, color_plane)) return 64;
fallthrough; case I915_FORMAT_MOD_Y_TILED: if (DISPLAY_VER(display) == 2 || HAS_128_BYTE_Y_TILING(i915)) return 128; else return 512; case I915_FORMAT_MOD_Yf_TILED_CCS: if (intel_fb_is_ccs_aux_plane(fb, color_plane)) return 128;
fallthrough; case I915_FORMAT_MOD_Yf_TILED: switch (cpp) { case 1: return 64; case 2: case 4: return 128; case 8: case 16: return 256; default:
MISSING_CASE(cpp); return cpp;
} break; default:
MISSING_CASE(fb->modifier); return cpp;
}
}
/* * Return the tile dimensions in pixel units, based on the tile block size. * The block covers the full GTT page sized tile on all tiled surfaces and * it's a 64 byte portion of the tile on TGL+ CCS surfaces.
*/ staticvoid intel_tile_block_dims(conststruct drm_framebuffer *fb, int color_plane, unsignedint *tile_width, unsignedint *tile_height)
{
intel_tile_dims(fb, color_plane, tile_width, tile_height);
if (intel_fb_is_gen12_ccs_aux_plane(fb, color_plane))
*tile_height = 1;
}
unsignedint intel_tile_row_size(conststruct drm_framebuffer *fb, int color_plane)
{ unsignedint tile_width, tile_height;
void intel_fb_plane_get_subsampling(int *hsub, int *vsub, conststruct drm_framebuffer *fb, int color_plane)
{ int main_plane;
if (color_plane == 0) {
*hsub = 1;
*vsub = 1;
return;
}
/* * TODO: Deduct the subsampling from the char block for all CCS * formats and planes.
*/ if (!intel_fb_is_gen12_ccs_aux_plane(fb, color_plane)) {
*hsub = fb->format->hsub;
*vsub = fb->format->vsub;
/* * The min stride check in the core framebuffer_check() function * assumes that format->hsub applies to every plane except for the * first plane. That's incorrect for the CCS AUX plane of the first * plane, but for the above check to pass we must define the block * width with that subsampling applied to it. Adjust the width here * accordingly, so we can calculate the actual subsampling factor.
*/ if (main_plane == 0)
*hsub *= fb->format->hsub;
*vsub = 32;
}
staticvoid intel_fb_plane_dims(conststruct intel_framebuffer *fb, int color_plane, int*w, int *h)
{ int main_plane = intel_fb_is_ccs_aux_plane(&fb->base, color_plane) ?
skl_ccs_to_main_plane(&fb->base, color_plane) : 0; unsignedint main_width = fb->base.width; unsignedint main_height = fb->base.height; int main_hsub, main_vsub; int hsub, vsub;
intel_adjust_tile_offset(x, y, tile_width, tile_height,
tile_size, pitch_tiles,
old_offset, new_offset);
} else {
intel_adjust_linear_offset(x, y, cpp, pitch,
old_offset, new_offset);
}
return new_offset;
}
/* * Adjust the tile offset by moving the difference into * the x/y offsets.
*/
u32 intel_plane_adjust_aligned_offset(int *x, int *y, conststruct intel_plane_state *plane_state, int color_plane,
u32 old_offset, u32 new_offset)
{ return intel_adjust_aligned_offset(x, y, plane_state->hw.fb, color_plane,
plane_state->hw.rotation,
plane_state->view.color_plane[color_plane].mapping_stride,
old_offset, new_offset);
}
/* * Computes the aligned offset to the base tile and adjusts * x, y. bytes per pixel is assumed to be a power-of-two. * * In the 90/270 rotated case, x and y are assumed * to be already rotated to match the rotated GTT view, and * pitch is the tile_height aligned framebuffer height. * * This function is used when computing the derived information * under intel_framebuffer, so using any of that information * here is not allowed. Anything under drm_framebuffer can be * used. This is why the user has to pass in the pitch since it * is specified in the rotated orientation.
*/ static u32 intel_compute_aligned_offset(struct intel_display *display, int *x, int *y, conststruct drm_framebuffer *fb, int color_plane, unsignedint pitch, unsignedint rotation, unsignedint alignment)
{ unsignedint cpp = fb->format->cpp[color_plane];
u32 offset, offset_aligned;
/* Catch potential overflows early */ if (check_add_overflow(mul_u32_u32(height, fb->pitches[color_plane]),
fb->offsets[color_plane], &unused)) {
drm_dbg_kms(display->drm, "Bad offset 0x%08x or pitch %d for color plane %d\n",
fb->offsets[color_plane], fb->pitches[color_plane],
color_plane); return -ERANGE;
}
*x = 0;
*y = 0;
intel_adjust_aligned_offset(x, y,
fb, color_plane, DRM_MODE_ROTATE_0,
fb->pitches[color_plane],
fb->offsets[color_plane], 0);
return 0;
}
staticint intel_fb_check_ccs_xy(conststruct drm_framebuffer *fb, int ccs_plane, int x, int y)
{ struct intel_display *display = to_intel_display(fb->dev); conststruct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); int main_plane; int hsub, vsub; int tile_width, tile_height; int ccs_x, ccs_y; int main_x, main_y;
if (!intel_fb_is_ccs_aux_plane(fb, ccs_plane)) return 0;
/* * While all the tile dimensions are based on a 2k or 4k GTT page size * here the main and CCS coordinates must match only within a (64 byte * on TGL+) block inside the tile.
*/
intel_tile_block_dims(fb, ccs_plane, &tile_width, &tile_height);
intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
/* * CCS doesn't have its own x/y offset register, so the intra CCS tile * x/y offsets must match between CCS and the main surface.
*/ if (main_x != ccs_x || main_y != ccs_y) {
drm_dbg_kms(display->drm, "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
main_x, main_y, ccs_x, ccs_y,
intel_fb->normal_view.color_plane[main_plane].x,
intel_fb->normal_view.color_plane[main_plane].y,
x, y); return -EINVAL;
}
/* We don't want to deal with remapping with cursors */ if (plane->id == PLANE_CURSOR) returnfalse;
/* * The display engine limits already match/exceed the * render engine limits, so not much point in remapping. * Would also need to deal with the fence POT alignment * and gen2 2KiB GTT tile size.
*/ if (DISPLAY_VER(display) < 4) returnfalse;
/* * The new CCS hash mode isn't compatible with remapping as * the virtual address of the pages affects the compressed data.
*/ if (intel_fb_is_ccs_modifier(fb->modifier)) returnfalse;
/* Linear needs a page aligned stride for remapping */ if (fb->modifier == DRM_FORMAT_MOD_LINEAR) { unsignedint alignment = intel_tile_size(display) - 1;
for (i = 0; i < fb->format->num_planes; i++) { if (fb->pitches[i] & alignment) returnfalse;
}
}
/* * No remapping for invisible planes since we don't have * an actual source viewport to remap.
*/ if (!plane_state->uapi.visible) returnfalse;
if (!intel_plane_can_remap(plane_state)) returnfalse;
/* * FIXME: aux plane limits on gen9+ are * unclear in Bspec, for now no checking.
*/
stride = intel_fb_pitch(fb, 0, rotation);
max_stride = plane->max_stride(plane, fb->base.format->format,
fb->base.modifier, rotation);
return stride > max_stride;
}
staticint convert_plane_offset_to_xy(conststruct intel_framebuffer *fb, int color_plane, int plane_width, int *x, int *y)
{ struct intel_display *display = to_intel_display(fb->base.dev); struct drm_gem_object *obj = intel_fb_bo(&fb->base); int ret;
ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane); if (ret) {
drm_dbg_kms(display->drm, "bad fb plane %d offset: 0x%x\n",
color_plane, fb->base.offsets[color_plane]); return ret;
}
ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y); if (ret) return ret;
/* * The fence (if used) is aligned to the start of the object * so having the framebuffer wrap around across the edge of the * fenced region doesn't really work. We have no API to configure * the fence start offset within the object (nor could we probably * on gen2/3). So it's just easier if we just require that the * fb layout agrees with the fence layout. We already check that the * fb stride matches the fence stride elsewhere.
*/ if (color_plane == 0 && intel_bo_is_tiled(obj) &&
(*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) {
drm_dbg_kms(display->drm, "bad fb plane %d offset: 0x%x\n",
color_plane, fb->base.offsets[color_plane]); return -EINVAL;
}
return 0;
}
static u32 calc_plane_aligned_offset(conststruct intel_framebuffer *fb, int color_plane, int *x, int *y)
{ struct intel_display *display = to_intel_display(fb->base.dev); unsignedint tile_size = intel_tile_size(display);
u32 offset;
offset = intel_compute_aligned_offset(display, x, y, &fb->base, color_plane,
fb->base.pitches[color_plane],
DRM_MODE_ROTATE_0,
tile_size);
staticunsignedint
plane_view_dst_stride_tiles(conststruct intel_framebuffer *fb, int color_plane, unsignedint pitch_tiles)
{ if (intel_fb_needs_pot_stride_remap(fb)) { /* * ADL_P, the only platform needing a POT stride has a minimum * of 8 main surface tiles.
*/ return roundup_pow_of_two(max(pitch_tiles, 8u));
} else { return pitch_tiles;
}
}
/* rotate the x/y offsets to match the GTT view */
drm_rect_init(&r, x, y, dims->width, dims->height);
drm_rect_rotate(&r,
remap_info->width * tile_width,
remap_info->height * tile_height,
DRM_MODE_ROTATE_270);
/* rotate the tile dimensions to match the GTT view */
swap(tile_width, tile_height);
} else {
drm_WARN_ON(display->drm, view->gtt.type != I915_GTT_VIEW_REMAPPED);
/* * The hardware automagically calculates the CCS AUX surface * stride from the main surface stride so can't really remap a * smaller subset (unless we'd remap in whole AUX page units).
*/ if (intel_fb_needs_pot_stride_remap(fb) &&
intel_fb_is_ccs_modifier(fb->base.modifier))
dst_stride = remap_info->src_stride; else
dst_stride = remap_info->width;
/* * We only keep the x/y offsets, so push all of the gtt offset into * the x/y offsets. x,y will hold the first pixel of the framebuffer * plane from the start of the remapped/rotated gtt mapping.
*/ if (remap_info->linear)
intel_adjust_linear_offset(&color_plane_info->x, &color_plane_info->y,
fb->base.format->cpp[color_plane],
color_plane_info->mapping_stride,
gtt_offset * tile_size, 0); else
intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y,
tile_width, tile_height,
tile_size, remap_info->dst_stride,
gtt_offset * tile_size, 0);
return size;
}
#undef assign_chk_ovf
/* Return number of tiles @color_plane needs. */ staticunsignedint
calc_plane_normal_size(conststruct intel_framebuffer *fb, int color_plane, conststruct fb_plane_view_dims *dims, int x, int y)
{ unsignedint tiles;
if (is_surface_linear(&fb->base, color_plane)) {
tiles = plane_view_linear_tiles(fb, color_plane, dims, x, y);
} else {
tiles = plane_view_src_stride_tiles(fb, color_plane, dims) *
plane_view_height_tiles(fb, color_plane, dims, y); /* * If the plane isn't horizontally tile aligned, * we need one more tile.
*/ if (x != 0)
tiles++;
}
if (intel_fb_supports_90_270_rotation(fb))
intel_fb_view_init(display, &fb->rotated_view, I915_GTT_VIEW_ROTATED); if (intel_fb_needs_pot_stride_remap(fb))
intel_fb_view_init(display, &fb->remapped_view, I915_GTT_VIEW_REMAPPED);
for (i = 0; i < num_planes; i++) { struct fb_plane_view_dims view_dims; unsignedint width, height; unsignedint size;
u32 offset; int x, y; int ret;
/* * Plane 2 of Render Compression with Clear Color fb modifier * is consumed by the driver and not passed to DE. Skip the * arithmetic related to alignment and offset calculation.
*/ if (is_gen12_ccs_cc_plane(&fb->base, i)) { unsignedint end;
if (!IS_ALIGNED(fb->base.offsets[i], 64)) {
drm_dbg_kms(display->drm, "fb misaligned clear color plane %d offset (0x%x)\n",
i, fb->base.offsets[i]); return -EINVAL;
}
if (check_add_overflow(fb->base.offsets[i], 64, &end)) {
drm_dbg_kms(display->drm, "fb bad clear color plane %d offset (0x%x)\n",
i, fb->base.offsets[i]); return -EINVAL;
}
ret = convert_plane_offset_to_xy(fb, i, width, &x, &y); if (ret) return ret;
init_plane_view_dims(fb, i, width, height, &view_dims);
/* * First pixel of the framebuffer from * the start of the normal gtt mapping.
*/
fb->normal_view.color_plane[i].x = x;
fb->normal_view.color_plane[i].y = y;
fb->normal_view.color_plane[i].mapping_stride = fb->base.pitches[i];
fb->normal_view.color_plane[i].scanout_stride =
fb->normal_view.color_plane[i].mapping_stride;
offset = calc_plane_aligned_offset(fb, i, &x, &y);
if (intel_fb_supports_90_270_rotation(fb))
gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims,
offset, gtt_offset_rotated, x, y,
&fb->rotated_view);
if (intel_fb_needs_pot_stride_remap(fb))
gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims,
offset, gtt_offset_remapped, x, y,
&fb->remapped_view);
size = calc_plane_normal_size(fb, i, &view_dims, x, y); /* how many tiles in total needed in the bo */
max_size = max(max_size, offset + size);
}
if (mul_u32_u32(max_size, tile_size) > obj->size) {
drm_dbg_kms(display->drm, "fb too big for bo (need %llu bytes, have %zu bytes)\n",
mul_u32_u32(max_size, tile_size), obj->size); return -EINVAL;
}
/* Make src coordinates relative to the viewport */
drm_rect_translate(&plane_state->uapi.src,
-(src_x << 16), -(src_y << 16));
/* Rotate src coordinates to match rotated GTT view */ if (drm_rotation_90_or_270(rotation))
drm_rect_rotate(&plane_state->uapi.src,
src_w << 16, src_h << 16,
DRM_MODE_ROTATE_270);
for (i = 0; i < num_planes; i++) { unsignedint hsub = i ? fb->format->hsub : 1; unsignedint vsub = i ? fb->format->vsub : 1; struct fb_plane_view_dims view_dims; unsignedint width, height; unsignedint x, y;
u32 offset;
x = src_x / hsub;
y = src_y / vsub;
width = src_w / hsub;
height = src_h / vsub;
init_plane_view_dims(intel_fb, i, width, height, &view_dims);
/* * First pixel of the src viewport from the * start of the normal gtt mapping.
*/
x += intel_fb->normal_view.color_plane[i].x;
y += intel_fb->normal_view.color_plane[i].y;
offset = calc_plane_aligned_offset(intel_fb, i, &x, &y);
gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims,
offset, gtt_offset, x, y,
&plane_state->view);
}
}
/* * Convert the x/y offsets into a linear offset. * Only valid with 0/180 degree rotation, which is fine since linear * offset is only used with linear buffers on pre-hsw and tiled buffers * with gen2/3, and 90/270 degree rotations isn't supported on any of them.
*/
u32 intel_fb_xy_to_linear(int x, int y, conststruct intel_plane_state *plane_state, int color_plane)
{ conststruct drm_framebuffer *fb = plane_state->hw.fb; unsignedint cpp = fb->format->cpp[color_plane]; unsignedint pitch = plane_state->view.color_plane[color_plane].mapping_stride;
return y * pitch + x * cpp;
}
/* * Add the x/y offsets derived from fb->offsets[] to the user * specified plane src x/y offsets. The resulting x/y offsets * specify the start of scanout from the beginning of the gtt mapping.
*/ void intel_add_fb_offsets(int *x, int *y, conststruct intel_plane_state *plane_state, int color_plane)
if (is_surface_linear(fb, color_plane)) { unsignedint max_stride = intel_plane_fb_max_stride(display->drm,
fb->format->format,
fb->modifier);
/* * To make remapping with linear generally feasible * we need the stride to be page aligned.
*/ if (fb->pitches[color_plane] > max_stride &&
!intel_fb_is_ccs_modifier(fb->modifier)) return intel_tile_size(display); else return 64;
}
tile_width = intel_tile_width_bytes(fb, color_plane); if (intel_fb_is_ccs_modifier(fb->modifier)) { /* * On TGL the surface stride must be 4 tile aligned, mapped by * one 64 byte cacheline on the CCS AUX surface.
*/ if (DISPLAY_VER(display) >= 12)
tile_width *= 4; /* * Display WA #0531: skl,bxt,kbl,glk * * Render decompression and plane width > 3840 * combined with horizontal panning requires the * plane stride to be a multiple of 4. We'll just * require the entire fb to accommodate that to avoid * potential runtime errors at plane configuration time.
*/ elseif ((DISPLAY_VER(display) == 9 || display->platform.geminilake) &&
color_plane == 0 && fb->width > 3840)
tile_width *= 4;
} return tile_width;
}
/* * We ignore stride for all invisible planes that * can be remapped. Otherwise we could end up * with a false positive when the remapping didn't * kick in due the plane being invisible.
*/ if (intel_plane_can_remap(plane_state) &&
!plane_state->uapi.visible) return 0;
/* FIXME other color planes? */
stride = plane_state->view.color_plane[0].mapping_stride;
max_stride = plane->max_stride(plane, fb->format->format,
fb->modifier, rotation);
if (intel_plane_needs_remap(plane_state)) {
intel_plane_remap_gtt(plane_state);
/* * Sometimes even remapping can't overcome * the stride limitations :( Can happen with * big plane sizes and suitably misaligned * offsets.
*/ return intel_plane_check_stride(plane_state);
}
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.