/* * Copyright 2018 Red Hat 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.
*/ #include"wndw.h" #include"wimm.h" #include"handles.h"
/* I8 format without an input LUT makes no sense, and the * HW error-checks for this. * * In order to handle legacy gamma, when there's no input * LUT we need to steal the output LUT and use it instead.
*/ if (!ilut && asyw->state.fb->format->format == DRM_FORMAT_C8) { /* This should be an error, but there's legacy clients * that do a modeset before providing a gamma table. * * We keep the window disabled to avoid angering HW.
*/ if (!(ilut = asyh->state.gamma_lut)) {
asyw->visible = false; return 0;
}
/* Fetch the assembly state for the head the window will belong to, * and determine whether the window will be visible.
*/ if (asyw->state.crtc) {
asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); if (IS_ERR(asyh)) return PTR_ERR(asyh);
modeset = drm_atomic_crtc_needs_modeset(&asyh->state);
asyw->visible = asyh->state.active;
} else {
asyw->visible = false;
}
/* Fetch assembly state for the head the window used to belong to. */ if (armw->state.crtc) {
harm = nv50_head_atom_get(asyw->state.state, armw->state.crtc); if (IS_ERR(harm)) return PTR_ERR(harm);
}
/* LUT configuration can potentially cause the window to be disabled. */ if (asyw->visible && wndw->func->xlut_set &&
(!armw->visible ||
asyh->state.color_mgmt_changed ||
asyw->state.fb->format->format !=
armw->state.fb->format->format)) {
ret = nv50_wndw_atomic_check_lut(wndw, armw, asyw, asyh); if (ret) return ret;
}
/* Calculate new window state. */ if (asyw->visible) {
ret = nv50_wndw_atomic_check_acquire(wndw, modeset,
armw, asyw, asyh); if (ret) return ret;
/* Aside from the obvious case where the window is actively being * disabled, we might also need to temporarily disable the window * when performing certain modeset operations.
*/ if (!asyw->visible || modeset) {
asyw->clr.ntfy = armw->ntfy.handle != 0;
asyw->clr.sema = armw->sema.handle != 0;
asyw->clr.xlut = armw->xlut.handle != 0; if (asyw->clr.xlut && asyw->visible)
asyw->set.xlut = asyw->xlut.handle != 0;
asyw->clr.csc = armw->csc.valid; if (wndw->func->image_clr)
asyw->clr.image = armw->image.handle[0] != 0;
}
NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, fb); if (!asyw->state.fb) return 0;
nvbo = nouveau_gem_object(fb->obj[0]);
ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, true); if (ret) return ret;
if (wndw->ctxdma.parent) { if (wndw->wndw.base.user.oclass < GB202_DISP_WINDOW_CHANNEL_DMA) {
ctxdma = nv50_wndw_ctxdma_new(wndw, fb); if (IS_ERR(ctxdma)) {
nouveau_bo_unpin(nvbo); return PTR_ERR(ctxdma);
}
if (asyw->visible)
asyw->image.handle[0] = ctxdma->object.handle;
} else { /* No CTXDMAs on Blackwell. */ if (asyw->visible) { /* "handle != NULL_HANDLE" is used to determine enable status * in a number of places, so fill in a fake object handle.
*/
asyw->image.handle[0] = NV50_DISP_HANDLE_WNDW_CTX(0);
}
}
}
ret = drm_gem_plane_helper_prepare_fb(plane, state); if (ret) return ret;
asyw->image.offset[0] = nvbo->offset;
if (wndw->func->prepare) {
asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); if (IS_ERR(asyh)) return PTR_ERR(asyh);
wndw->func->prepare(wndw, asyh, asyw);
}
return 0;
}
/* Only used by drm_panic get_scanout_buffer() and set_pixel(), so it is * protected by the drm panic spinlock
*/ static u32 nv50_panic_blk_h;
/* Return the framebuffer offset of the start of the block where pixel(x,y) is */ static u32
nv50_get_block_off(unsignedint x, unsignedint y, unsignedint pitch)
{
u32 blk_x, blk_y, blk_columns;
/* Turing and later have 2 level of tiles inside the block */ staticvoid
nv50_set_pixel_swizzle(struct drm_scanout_buffer *sb, unsignedint x, unsignedint y, u32 color)
{
u32 blk_off, off, swizzle;
blk_off = nv50_get_block_off(x, y, sb->pitch[0]);
y = y % nv50_panic_blk_h;
/* Inside the block, use the fast address swizzle to compute the offset * For nvidia blocklinear, bit order is yn..y3 x3 y2 x2 y1 y0 x1 x0
*/
swizzle = (x & 3) | (y & 3) << 2 | (x & 4) << 2 | (y & 4) << 3;
swizzle |= (x & 8) << 3 | (y >> 3) << 7;
off = blk_off + swizzle * 4;
nouveau_framebuffer_get_layout(fb, &tile_mode, &kind); if (kind) { /* If tiling is enabled, use set_pixel() to display correctly. * Only handle 32bits format for now.
*/ if (fb->format->cpp[0] != 4) return -EOPNOTSUPP;
nv50_panic_blk_h = nouveau_get_gob_height(family) *
nouveau_get_gobs_in_block(tile_mode, chipset);
/* This function assumes the format has already been validated against the plane * and the modifier was validated against the device-wide modifier list at FB * creation time.
*/ staticbool nv50_plane_format_mod_supported(struct drm_plane *plane,
u32 format, u64 modifier)
{ struct nouveau_drm *drm = nouveau_drm(plane->dev); conststruct drm_format_info *info = drm_format_info(format);
uint8_t i;
/* All chipsets can display all formats in linear layout */ if (modifier == DRM_FORMAT_MOD_LINEAR) returntrue;
for (i = 0; i < info->num_planes; i++) if ((info->cpp[i] != 4) && kind != 0x70) returnfalse;
} elseif (drm->client.device.info.chipset >= 0x1b2) { const uint8_t slayout = ((modifier >> 22) & 0x1) |
((modifier >> 25) & 0x6);
if (!format) returnfalse;
/* * Note in practice this implies only formats where cpp is equal * for each plane, or >= 4 for all planes, are supported.
*/ for (i = 0; i < info->num_planes; i++) { if (((info->cpp[i] == 2) && slayout != 3) ||
((info->cpp[i] == 1) && slayout != 2) ||
((info->cpp[i] >= 4) && slayout != 1)) returnfalse;
/* 24-bit not supported. It has yet another layout */
WARN_ON(info->cpp[i] == 3);
}
}
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.