forked from Minki/linux
Merge tag 'vmwgfx-next-2018-12-05' of git://people.freedesktop.org/~thomash/linux into drm-next
Pull request of 2018-12-05 Page flip with damage by Deepak and others, Various vmwgfx minor fixes anc cleanups. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Hellstrom <thellstrom@vmware.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181205103554.3675-1-thellstrom@vmware.com
This commit is contained in:
commit
1f9a5dce35
@ -554,6 +554,18 @@ Plane Composition Properties
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_blend.c
|
||||
:export:
|
||||
|
||||
FB_DAMAGE_CLIPS
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_damage_helper.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_damage_helper.h
|
||||
:internal:
|
||||
|
||||
Color Management Properties
|
||||
---------------------------
|
||||
|
||||
|
@ -4781,10 +4781,8 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVER FOR VMWARE VIRTUAL GPU
|
||||
M: "VMware Graphics" <linux-graphics-maintainer@vmware.com>
|
||||
M: Sinclair Yeh <syeh@vmware.com>
|
||||
M: Thomas Hellstrom <thellstrom@vmware.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
T: git git://people.freedesktop.org/~syeh/repos_linux
|
||||
T: git git://people.freedesktop.org/~thomash/linux
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/vmwgfx/
|
||||
|
@ -37,7 +37,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
|
||||
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
|
||||
drm_simple_kms_helper.o drm_modeset_helper.o \
|
||||
drm_scdc_helper.o drm_gem_framebuffer_helper.o \
|
||||
drm_atomic_state_helper.o
|
||||
drm_atomic_state_helper.o drm_damage_helper.o
|
||||
|
||||
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
|
||||
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
|
||||
|
@ -531,6 +531,8 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
|
||||
struct drm_crtc *crtc = new_plane_state->crtc;
|
||||
const struct drm_framebuffer *fb = new_plane_state->fb;
|
||||
unsigned int fb_width, fb_height;
|
||||
struct drm_mode_rect *clips;
|
||||
uint32_t num_clips;
|
||||
int ret;
|
||||
|
||||
/* either *both* CRTC and FB must be set, or neither */
|
||||
@ -604,6 +606,26 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
clips = drm_plane_get_damage_clips(new_plane_state);
|
||||
num_clips = drm_plane_get_damage_clips_count(new_plane_state);
|
||||
|
||||
/* Make sure damage clips are valid and inside the fb. */
|
||||
while (num_clips > 0) {
|
||||
if (clips->x1 >= clips->x2 ||
|
||||
clips->y1 >= clips->y2 ||
|
||||
clips->x1 < 0 ||
|
||||
clips->y1 < 0 ||
|
||||
clips->x2 > fb_width ||
|
||||
clips->y2 > fb_height) {
|
||||
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n",
|
||||
plane->base.id, plane->name, clips->x1,
|
||||
clips->y1, clips->x2, clips->y2);
|
||||
return -EINVAL;
|
||||
}
|
||||
clips++;
|
||||
num_clips--;
|
||||
}
|
||||
|
||||
if (plane_switching_crtc(old_plane_state, new_plane_state)) {
|
||||
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
|
||||
plane->base.id, plane->name);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_writeback.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <linux/dma-fence.h>
|
||||
|
||||
#include "drm_crtc_helper_internal.h"
|
||||
@ -862,6 +863,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
|
||||
|
||||
drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);
|
||||
|
||||
drm_atomic_helper_check_plane_damage(state, new_plane_state);
|
||||
|
||||
if (!funcs || !funcs->atomic_check)
|
||||
continue;
|
||||
|
||||
|
@ -517,6 +517,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
bool replaced = false;
|
||||
int ret;
|
||||
|
||||
if (property == config->prop_fb_id) {
|
||||
struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
|
||||
@ -570,6 +572,14 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
|
||||
state->color_encoding = val;
|
||||
} else if (property == plane->color_range_property) {
|
||||
state->color_range = val;
|
||||
} else if (property == config->prop_fb_damage_clips) {
|
||||
ret = drm_atomic_replace_property_blob_from_id(dev,
|
||||
&state->fb_damage_clips,
|
||||
val,
|
||||
-1,
|
||||
sizeof(struct drm_rect),
|
||||
&replaced);
|
||||
return ret;
|
||||
} else if (plane->funcs->atomic_set_property) {
|
||||
return plane->funcs->atomic_set_property(plane, state,
|
||||
property, val);
|
||||
@ -625,6 +635,9 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
|
||||
*val = state->color_encoding;
|
||||
} else if (property == plane->color_range_property) {
|
||||
*val = state->color_range;
|
||||
} else if (property == config->prop_fb_damage_clips) {
|
||||
*val = (state->fb_damage_clips) ?
|
||||
state->fb_damage_clips->base.id : 0;
|
||||
} else if (plane->funcs->atomic_get_property) {
|
||||
return plane->funcs->atomic_get_property(plane, state, property, val);
|
||||
} else {
|
||||
|
334
drivers/gpu/drm/drm_damage_helper.c
Normal file
334
drivers/gpu/drm/drm_damage_helper.c
Normal file
@ -0,0 +1,334 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* 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, sub license, 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 (including the
|
||||
* next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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:
|
||||
* Deepak Rawat <drawat@vmware.com>
|
||||
* Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
*
|
||||
* FB_DAMAGE_CLIPS is an optional plane property which provides a means to
|
||||
* specify a list of damage rectangles on a plane in framebuffer coordinates of
|
||||
* the framebuffer attached to the plane. In current context damage is the area
|
||||
* of plane framebuffer that has changed since last plane update (also called
|
||||
* page-flip), irrespective of whether currently attached framebuffer is same as
|
||||
* framebuffer attached during last plane update or not.
|
||||
*
|
||||
* FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers
|
||||
* to optimize internally especially for virtual devices where each framebuffer
|
||||
* change needs to be transmitted over network, usb, etc.
|
||||
*
|
||||
* Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can
|
||||
* ignore damage clips property and in that case driver will do a full plane
|
||||
* update. In case damage clips are provided then it is guaranteed that the area
|
||||
* inside damage clips will be updated to plane. For efficiency driver can do
|
||||
* full update or can update more than specified in damage clips. Since driver
|
||||
* is free to read more, user-space must always render the entire visible
|
||||
* framebuffer. Otherwise there can be corruptions. Also, if a user-space
|
||||
* provides damage clips which doesn't encompass the actual damage to
|
||||
* framebuffer (since last plane update) can result in incorrect rendering.
|
||||
*
|
||||
* FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an
|
||||
* array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates,
|
||||
* damage clips are not in 16.16 fixed point. Similar to plane src in
|
||||
* framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are
|
||||
* inclusive and x2/y2 are exclusive. While kernel does not error for overlapped
|
||||
* damage clips, it is strongly discouraged.
|
||||
*
|
||||
* Drivers that are interested in damage interface for plane should enable
|
||||
* FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().
|
||||
* Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and
|
||||
* drm_atomic_helper_damage_iter_next() helper iterator function to get damage
|
||||
* rectangles clipped to &drm_plane_state.src.
|
||||
*/
|
||||
|
||||
static void convert_clip_rect_to_rect(const struct drm_clip_rect *src,
|
||||
struct drm_mode_rect *dest,
|
||||
uint32_t num_clips, uint32_t src_inc)
|
||||
{
|
||||
while (num_clips > 0) {
|
||||
dest->x1 = src->x1;
|
||||
dest->y1 = src->y1;
|
||||
dest->x2 = src->x2;
|
||||
dest->y2 = src->y2;
|
||||
src += src_inc;
|
||||
dest++;
|
||||
num_clips--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property.
|
||||
* @plane: Plane on which to enable damage clips property.
|
||||
*
|
||||
* This function lets driver to enable the damage clips property on a plane.
|
||||
*/
|
||||
void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
|
||||
drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
|
||||
0);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_check_plane_damage - Verify plane damage on atomic_check.
|
||||
* @state: The driver state object.
|
||||
* @plane_state: Plane state for which to verify damage.
|
||||
*
|
||||
* This helper function makes sure that damage from plane state is discarded
|
||||
* for full modeset. If there are more reasons a driver would want to do a full
|
||||
* plane update rather than processing individual damage regions, then those
|
||||
* cases should be taken care of here.
|
||||
*
|
||||
* Note that &drm_plane_state.fb_damage_clips == NULL in plane state means that
|
||||
* full plane update should happen. It also ensure helper iterator will return
|
||||
* &drm_plane_state.src as damage.
|
||||
*/
|
||||
void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
if (plane_state->crtc) {
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state,
|
||||
plane_state->crtc);
|
||||
|
||||
if (WARN_ON(!crtc_state))
|
||||
return;
|
||||
|
||||
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
|
||||
drm_property_blob_put(plane_state->fb_damage_clips);
|
||||
plane_state->fb_damage_clips = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_dirtyfb - Helper for dirtyfb.
|
||||
* @fb: DRM framebuffer.
|
||||
* @file_priv: Drm file for the ioctl call.
|
||||
* @flags: Dirty fb annotate flags.
|
||||
* @color: Color for annotate fill.
|
||||
* @clips: Dirty region.
|
||||
* @num_clips: Count of clip in clips.
|
||||
*
|
||||
* A helper to implement &drm_framebuffer_funcs.dirty using damage interface
|
||||
* during plane update. If num_clips is 0 then this helper will do a full plane
|
||||
* update. This is the same behaviour expected by DIRTFB IOCTL.
|
||||
*
|
||||
* Note that this helper is blocking implementation. This is what current
|
||||
* drivers and userspace expect in their DIRTYFB IOCTL implementation, as a way
|
||||
* to rate-limit userspace and make sure its rendering doesn't get ahead of
|
||||
* uploading new data too much.
|
||||
*
|
||||
* Return: Zero on success, negative errno on failure.
|
||||
*/
|
||||
int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv, unsigned int flags,
|
||||
unsigned int color, struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
{
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_property_blob *damage = NULL;
|
||||
struct drm_mode_rect *rects = NULL;
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_plane *plane;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* When called from ioctl, we are interruptable, but not when called
|
||||
* internally (ie. defio worker)
|
||||
*/
|
||||
drm_modeset_acquire_init(&ctx,
|
||||
file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0);
|
||||
|
||||
state = drm_atomic_state_alloc(fb->dev);
|
||||
if (!state) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
state->acquire_ctx = &ctx;
|
||||
|
||||
if (clips) {
|
||||
uint32_t inc = 1;
|
||||
|
||||
if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
|
||||
inc = 2;
|
||||
num_clips /= 2;
|
||||
}
|
||||
|
||||
rects = kcalloc(num_clips, sizeof(*rects), GFP_KERNEL);
|
||||
if (!rects) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
convert_clip_rect_to_rect(clips, rects, num_clips, inc);
|
||||
damage = drm_property_create_blob(fb->dev,
|
||||
num_clips * sizeof(*rects),
|
||||
rects);
|
||||
if (IS_ERR(damage)) {
|
||||
ret = PTR_ERR(damage);
|
||||
damage = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
drm_for_each_plane(plane, fb->dev) {
|
||||
struct drm_plane_state *plane_state;
|
||||
|
||||
if (plane->state->fb != fb)
|
||||
continue;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state, plane);
|
||||
if (IS_ERR(plane_state)) {
|
||||
ret = PTR_ERR(plane_state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
drm_property_replace_blob(&plane_state->fb_damage_clips,
|
||||
damage);
|
||||
}
|
||||
|
||||
ret = drm_atomic_commit(state);
|
||||
|
||||
out:
|
||||
if (ret == -EDEADLK) {
|
||||
drm_atomic_state_clear(state);
|
||||
ret = drm_modeset_backoff(&ctx);
|
||||
if (!ret)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
drm_property_blob_put(damage);
|
||||
kfree(rects);
|
||||
drm_atomic_state_put(state);
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_dirtyfb);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_damage_iter_init - Initialize the damage iterator.
|
||||
* @iter: The iterator to initialize.
|
||||
* @old_state: Old plane state for validation.
|
||||
* @new_state: Plane state from which to iterate the damage clips.
|
||||
*
|
||||
* Initialize an iterator, which clips plane damage
|
||||
* &drm_plane_state.fb_damage_clips to plane &drm_plane_state.src. This iterator
|
||||
* returns full plane src in case damage is not present because either
|
||||
* user-space didn't sent or driver discarded it (it want to do full plane
|
||||
* update). Currently this iterator returns full plane src in case plane src
|
||||
* changed but that can be changed in future to return damage.
|
||||
*
|
||||
* For the case when plane is not visible or plane update should not happen the
|
||||
* first call to iter_next will return false. Note that this helper use clipped
|
||||
* &drm_plane_state.src, so driver calling this helper should have called
|
||||
* drm_atomic_helper_check_plane_state() earlier.
|
||||
*/
|
||||
void
|
||||
drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
|
||||
const struct drm_plane_state *old_state,
|
||||
const struct drm_plane_state *state)
|
||||
{
|
||||
memset(iter, 0, sizeof(*iter));
|
||||
|
||||
if (!state || !state->crtc || !state->fb || !state->visible)
|
||||
return;
|
||||
|
||||
iter->clips = drm_helper_get_plane_damage_clips(state);
|
||||
iter->num_clips = drm_plane_get_damage_clips_count(state);
|
||||
|
||||
/* Round down for x1/y1 and round up for x2/y2 to catch all pixels */
|
||||
iter->plane_src.x1 = state->src.x1 >> 16;
|
||||
iter->plane_src.y1 = state->src.y1 >> 16;
|
||||
iter->plane_src.x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
|
||||
iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
|
||||
|
||||
if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
|
||||
iter->clips = 0;
|
||||
iter->num_clips = 0;
|
||||
iter->full_update = true;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_damage_iter_init);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_damage_iter_next - Advance the damage iterator.
|
||||
* @iter: The iterator to advance.
|
||||
* @rect: Return a rectangle in fb coordinate clipped to plane src.
|
||||
*
|
||||
* Since plane src is in 16.16 fixed point and damage clips are whole number,
|
||||
* this iterator round off clips that intersect with plane src. Round down for
|
||||
* x1/y1 and round up for x2/y2 for the intersected coordinate. Similar rounding
|
||||
* off for full plane src, in case it's returned as damage. This iterator will
|
||||
* skip damage clips outside of plane src.
|
||||
*
|
||||
* Return: True if the output is valid, false if reached the end.
|
||||
*
|
||||
* If the first call to iterator next returns false then it means no need to
|
||||
* update the plane.
|
||||
*/
|
||||
bool
|
||||
drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
|
||||
struct drm_rect *rect)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (iter->full_update) {
|
||||
*rect = iter->plane_src;
|
||||
iter->full_update = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
while (iter->curr_clip < iter->num_clips) {
|
||||
*rect = iter->clips[iter->curr_clip];
|
||||
iter->curr_clip++;
|
||||
|
||||
if (drm_rect_intersect(rect, &iter->plane_src)) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_damage_iter_next);
|
@ -297,6 +297,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
|
||||
return -ENOMEM;
|
||||
dev->mode_config.prop_crtc_id = prop;
|
||||
|
||||
prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "FB_DAMAGE_CLIPS",
|
||||
0);
|
||||
if (!prop)
|
||||
return -ENOMEM;
|
||||
dev->mode_config.prop_fb_damage_clips = prop;
|
||||
|
||||
prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
|
||||
"ACTIVE");
|
||||
if (!prop)
|
||||
|
@ -1,4 +1,5 @@
|
||||
test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
|
||||
test-drm_format.o test-drm_framebuffer.o
|
||||
test-drm_format.o test-drm_framebuffer.o \
|
||||
test-drm_damage_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
|
||||
|
@ -11,3 +11,24 @@ selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
|
||||
selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
|
||||
selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
|
||||
selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
|
||||
selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
|
||||
selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
|
||||
selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
|
||||
selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
|
||||
selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
|
||||
selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
|
||||
selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
|
||||
selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
|
||||
selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
|
||||
selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
|
||||
selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
|
||||
selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
|
||||
selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
|
||||
selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
|
||||
selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
|
||||
selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
|
||||
selftest(damage_iter_damage, igt_damage_iter_damage)
|
||||
selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
|
||||
selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
|
||||
selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
|
||||
selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
|
||||
|
811
drivers/gpu/drm/selftests/test-drm_damage_helper.c
Normal file
811
drivers/gpu/drm/selftests/test-drm_damage_helper.c
Normal file
@ -0,0 +1,811 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Test case for drm_damage_helper functions
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "drm_damage_helper: " fmt
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
|
||||
#include "test-drm_modeset_common.h"
|
||||
|
||||
static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
|
||||
int y2)
|
||||
{
|
||||
state->src.x1 = x1;
|
||||
state->src.y1 = y1;
|
||||
state->src.x2 = x2;
|
||||
state->src.y2 = y2;
|
||||
}
|
||||
|
||||
static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
|
||||
int y2)
|
||||
{
|
||||
r->x1 = x1;
|
||||
r->y1 = y1;
|
||||
r->x2 = x2;
|
||||
r->y2 = y2;
|
||||
}
|
||||
|
||||
static void set_damage_blob(struct drm_property_blob *damage_blob,
|
||||
struct drm_mode_rect *r, uint32_t size)
|
||||
{
|
||||
damage_blob->length = size;
|
||||
damage_blob->data = r;
|
||||
}
|
||||
|
||||
static void set_plane_damage(struct drm_plane_state *state,
|
||||
struct drm_property_blob *damage_blob)
|
||||
{
|
||||
state->fb_damage_clips = damage_blob;
|
||||
}
|
||||
|
||||
static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
|
||||
int x1, int y1, int x2, int y2)
|
||||
{
|
||||
/*
|
||||
* Round down x1/y1 and round up x2/y2. This is because damage is not in
|
||||
* 16.16 fixed point so to catch all pixels.
|
||||
*/
|
||||
int src_x1 = state->src.x1 >> 16;
|
||||
int src_y1 = state->src.y1 >> 16;
|
||||
int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
|
||||
int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
|
||||
|
||||
if (x1 >= x2 || y1 >= y2) {
|
||||
pr_err("Cannot have damage clip with no dimention.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
|
||||
pr_err("Damage cannot be outside rounded plane src.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
|
||||
pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src same as fb size. */
|
||||
set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
|
||||
set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x3fffe, 0x3fffe,
|
||||
0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
|
||||
set_plane_src(&state, 0x3fffe, 0x3fffe,
|
||||
0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src moved since old plane state. */
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 10 << 16, 10 << 16,
|
||||
(10 + 1024) << 16, (10 + 768) << 16);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src has fractional part and it moved since old plane state. */
|
||||
set_plane_src(&old_state, 0x3fffe, 0x3fffe,
|
||||
0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
|
||||
set_plane_src(&state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage_not_visible(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = false,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 0, "Should have no damage.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage_no_crtc(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = 0,
|
||||
.fb = &fb,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 0, "Should have no damage.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_no_damage_no_fb(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = 0,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 0, "Should have no damage.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_simple_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
/* Damage set to plane src */
|
||||
set_damage_clip(&damage, 0, 0, 1024, 768);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return damage when set.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_damage_clip(&damage, 256, 192, 768, 576);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return damage when set.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_intersect_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
/* Damage intersect with plane src. */
|
||||
set_damage_clip(&damage, 256, 192, 1360, 768);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return damage clipped to src.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_outside_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
/* Damage clip outside plane src */
|
||||
set_damage_clip(&damage, 1360, 1360, 1380, 1380);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 0, "Should have no damage.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_plane_src(&state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_damage_clip(&damage, 10, 10, 256, 330);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return damage when set.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_plane_src(&state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
/* Damage intersect with plane src. */
|
||||
set_damage_clip(&damage, 10, 1, 1360, 330);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src has fractional part. */
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_plane_src(&state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
/* Damage clip outside plane src */
|
||||
set_damage_clip(&damage, 1360, 1360, 1380, 1380);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 0, "Should have no damage.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src moved since old plane state. */
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 10 << 16, 10 << 16,
|
||||
(10 + 1024) << 16, (10 + 768) << 16);
|
||||
set_damage_clip(&damage, 20, 30, 256, 256);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage;
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
/* Plane src with fractional part moved since old plane state. */
|
||||
set_plane_src(&old_state, 0x3fffe, 0x3fffe,
|
||||
0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
|
||||
set_plane_src(&state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
/* Damage intersect with plane src. */
|
||||
set_damage_clip(&damage, 20, 30, 1360, 256);
|
||||
set_damage_blob(&damage_blob, &damage, sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_damage(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
/* 2 damage clips. */
|
||||
set_damage_clip(&damage[0], 20, 30, 200, 180);
|
||||
set_damage_clip(&damage[1], 240, 200, 280, 250);
|
||||
set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip) {
|
||||
if (num_hits == 0)
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
|
||||
if (num_hits == 1)
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
|
||||
num_hits++;
|
||||
}
|
||||
|
||||
FAIL(num_hits != 2, "Should return damage when set.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_damage_one_intersect(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_plane_src(&state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
/* 2 damage clips, one intersect plane src. */
|
||||
set_damage_clip(&damage[0], 20, 30, 200, 180);
|
||||
set_damage_clip(&damage[1], 2, 2, 1360, 1360);
|
||||
set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip) {
|
||||
if (num_hits == 0)
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
|
||||
if (num_hits == 1)
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
|
||||
num_hits++;
|
||||
}
|
||||
|
||||
FAIL(num_hits != 2, "Should return damage when set.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_damage_one_outside(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
|
||||
set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
|
||||
/* 2 damage clips, one outside plane src. */
|
||||
set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
|
||||
set_damage_clip(&damage[1], 240, 200, 280, 250);
|
||||
set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return damage when set.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_damage_src_moved(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = true,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_plane_src(&state, 0x3fffe, 0x3fffe,
|
||||
0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
|
||||
/* 2 damage clips, one outside plane src. */
|
||||
set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
|
||||
set_damage_clip(&damage[1], 240, 200, 280, 250);
|
||||
set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 1, "Should return round off plane src as damage.");
|
||||
FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igt_damage_iter_damage_not_visible(void *ignored)
|
||||
{
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_plane_state old_state;
|
||||
struct drm_property_blob damage_blob;
|
||||
struct drm_mode_rect damage[2];
|
||||
struct drm_rect clip;
|
||||
uint32_t num_hits = 0;
|
||||
|
||||
struct drm_framebuffer fb = {
|
||||
.width = 2048,
|
||||
.height = 2048
|
||||
};
|
||||
|
||||
struct drm_plane_state state = {
|
||||
.crtc = ZERO_SIZE_PTR,
|
||||
.fb = &fb,
|
||||
.visible = false,
|
||||
};
|
||||
|
||||
set_plane_src(&old_state, 0x40002, 0x40002,
|
||||
0x40002 + (1024 << 16), 0x40002 + (768 << 16));
|
||||
set_plane_src(&state, 0x3fffe, 0x3fffe,
|
||||
0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
|
||||
/* 2 damage clips, one outside plane src. */
|
||||
set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
|
||||
set_damage_clip(&damage[1], 240, 200, 280, 250);
|
||||
set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
|
||||
set_plane_damage(&state, &damage_blob);
|
||||
drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
FAIL(num_hits != 0, "Should not return any damage.");
|
||||
|
||||
return 0;
|
||||
}
|
@ -18,5 +18,26 @@ int igt_check_drm_format_block_width(void *ignored);
|
||||
int igt_check_drm_format_block_height(void *ignored);
|
||||
int igt_check_drm_format_min_pitch(void *ignored);
|
||||
int igt_check_drm_framebuffer_create(void *ignored);
|
||||
int igt_damage_iter_no_damage(void *ignored);
|
||||
int igt_damage_iter_no_damage_fractional_src(void *ignored);
|
||||
int igt_damage_iter_no_damage_src_moved(void *ignored);
|
||||
int igt_damage_iter_no_damage_fractional_src_moved(void *ignored);
|
||||
int igt_damage_iter_no_damage_not_visible(void *ignored);
|
||||
int igt_damage_iter_no_damage_no_crtc(void *ignored);
|
||||
int igt_damage_iter_no_damage_no_fb(void *ignored);
|
||||
int igt_damage_iter_simple_damage(void *ignored);
|
||||
int igt_damage_iter_single_damage(void *ignored);
|
||||
int igt_damage_iter_single_damage_intersect_src(void *ignored);
|
||||
int igt_damage_iter_single_damage_outside_src(void *ignored);
|
||||
int igt_damage_iter_single_damage_fractional_src(void *ignored);
|
||||
int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored);
|
||||
int igt_damage_iter_single_damage_outside_fractional_src(void *ignored);
|
||||
int igt_damage_iter_single_damage_src_moved(void *ignored);
|
||||
int igt_damage_iter_single_damage_fractional_src_moved(void *ignored);
|
||||
int igt_damage_iter_damage(void *ignored);
|
||||
int igt_damage_iter_damage_one_intersect(void *ignored);
|
||||
int igt_damage_iter_damage_one_outside(void *ignored);
|
||||
int igt_damage_iter_damage_src_moved(void *ignored);
|
||||
int igt_damage_iter_damage_not_visible(void *ignored);
|
||||
|
||||
#endif
|
||||
|
@ -665,7 +665,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
|
||||
mutex_init(&dev_priv->cmdbuf_mutex);
|
||||
mutex_init(&dev_priv->release_mutex);
|
||||
mutex_init(&dev_priv->binding_mutex);
|
||||
mutex_init(&dev_priv->requested_layout_mutex);
|
||||
mutex_init(&dev_priv->global_kms_state_mutex);
|
||||
ttm_lock_init(&dev_priv->reservation_sem);
|
||||
spin_lock_init(&dev_priv->resource_lock);
|
||||
|
@ -465,15 +465,6 @@ struct vmw_private {
|
||||
|
||||
uint32_t num_displays;
|
||||
|
||||
/*
|
||||
* Currently requested_layout_mutex is used to protect the gui
|
||||
* positionig state in display unit. With that use case currently this
|
||||
* mutex is only taken during layout ioctl and atomic check_modeset.
|
||||
* Other display unit state can be protected with this mutex but that
|
||||
* needs careful consideration.
|
||||
*/
|
||||
struct mutex requested_layout_mutex;
|
||||
|
||||
/*
|
||||
* Framebuffer info.
|
||||
*/
|
||||
@ -484,8 +475,6 @@ struct vmw_private {
|
||||
struct vmw_overlay *overlay_priv;
|
||||
struct drm_property *hotplug_mode_update_property;
|
||||
struct drm_property *implicit_placement_property;
|
||||
unsigned num_implicit;
|
||||
struct vmw_framebuffer *implicit_fb;
|
||||
struct mutex global_kms_state_mutex;
|
||||
spinlock_t cursor_lock;
|
||||
struct drm_atomic_state *suspend_state;
|
||||
|
@ -1738,7 +1738,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
|
||||
void *buf)
|
||||
{
|
||||
struct vmw_buffer_object *vmw_bo;
|
||||
int ret;
|
||||
|
||||
struct {
|
||||
uint32_t header;
|
||||
@ -1748,7 +1747,6 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
|
||||
return vmw_translate_guest_ptr(dev_priv, sw_context,
|
||||
&cmd->body.ptr,
|
||||
&vmw_bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -906,13 +906,10 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
|
||||
container_of(action, struct vmw_event_fence_action, action);
|
||||
struct drm_device *dev = eaction->dev;
|
||||
struct drm_pending_event *event = eaction->event;
|
||||
struct drm_file *file_priv;
|
||||
|
||||
|
||||
if (unlikely(event == NULL))
|
||||
return;
|
||||
|
||||
file_priv = event->file_priv;
|
||||
spin_lock_irq(&dev->event_lock);
|
||||
|
||||
if (likely(eaction->tv_sec != NULL)) {
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
|
||||
/* Might need a hrtimer here? */
|
||||
#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
|
||||
@ -456,21 +457,8 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_crtc *crtc = state->crtc;
|
||||
struct vmw_connector_state *vcs;
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
|
||||
|
||||
vcs = vmw_connector_state_to_vcs(du->connector.state);
|
||||
|
||||
/* Only one active implicit framebuffer at a time. */
|
||||
mutex_lock(&dev_priv->global_kms_state_mutex);
|
||||
if (vcs->is_implicit && dev_priv->implicit_fb &&
|
||||
!(dev_priv->num_implicit == 1 && du->active_implicit)
|
||||
&& dev_priv->implicit_fb != vfb) {
|
||||
DRM_ERROR("Multiple implicit framebuffers "
|
||||
"not supported.\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&dev_priv->global_kms_state_mutex);
|
||||
}
|
||||
|
||||
|
||||
@ -846,58 +834,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
|
||||
kfree(vfbs);
|
||||
}
|
||||
|
||||
static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
|
||||
struct drm_file *file_priv,
|
||||
unsigned flags, unsigned color,
|
||||
struct drm_clip_rect *clips,
|
||||
unsigned num_clips)
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
|
||||
struct vmw_framebuffer_surface *vfbs =
|
||||
vmw_framebuffer_to_vfbs(framebuffer);
|
||||
struct drm_clip_rect norect;
|
||||
int ret, inc = 1;
|
||||
|
||||
/* Legacy Display Unit does not support 3D */
|
||||
if (dev_priv->active_display_unit == vmw_du_legacy)
|
||||
return -EINVAL;
|
||||
|
||||
drm_modeset_lock_all(dev_priv->dev);
|
||||
|
||||
ret = ttm_read_lock(&dev_priv->reservation_sem, true);
|
||||
if (unlikely(ret != 0)) {
|
||||
drm_modeset_unlock_all(dev_priv->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!num_clips) {
|
||||
num_clips = 1;
|
||||
clips = &norect;
|
||||
norect.x1 = norect.y1 = 0;
|
||||
norect.x2 = framebuffer->width;
|
||||
norect.y2 = framebuffer->height;
|
||||
} else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) {
|
||||
num_clips /= 2;
|
||||
inc = 2; /* skip source rects */
|
||||
}
|
||||
|
||||
if (dev_priv->active_display_unit == vmw_du_screen_object)
|
||||
ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base,
|
||||
clips, NULL, NULL, 0, 0,
|
||||
num_clips, inc, NULL, NULL);
|
||||
else
|
||||
ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base,
|
||||
clips, NULL, NULL, 0, 0,
|
||||
num_clips, inc, NULL, NULL);
|
||||
|
||||
vmw_fifo_flush(dev_priv, false);
|
||||
ttm_read_unlock(&dev_priv->reservation_sem);
|
||||
|
||||
drm_modeset_unlock_all(dev_priv->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_readback - Perform a readback from the screen system to
|
||||
* a buffer-object backed framebuffer.
|
||||
@ -941,7 +877,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
|
||||
|
||||
static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
|
||||
.destroy = vmw_framebuffer_surface_destroy,
|
||||
.dirty = vmw_framebuffer_surface_dirty,
|
||||
.dirty = drm_atomic_helper_dirtyfb,
|
||||
};
|
||||
|
||||
static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
|
||||
@ -1084,16 +1020,6 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
|
||||
}
|
||||
|
||||
switch (dev_priv->active_display_unit) {
|
||||
case vmw_du_screen_target:
|
||||
ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL,
|
||||
clips, NULL, num_clips, increment,
|
||||
true, true, NULL);
|
||||
break;
|
||||
case vmw_du_screen_object:
|
||||
ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base,
|
||||
clips, NULL, num_clips,
|
||||
increment, true, NULL, NULL);
|
||||
break;
|
||||
case vmw_du_legacy:
|
||||
ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0,
|
||||
clips, num_clips, increment);
|
||||
@ -1112,9 +1038,25 @@ static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int flags, unsigned int color,
|
||||
struct drm_clip_rect *clips,
|
||||
unsigned int num_clips)
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
|
||||
|
||||
if (dev_priv->active_display_unit == vmw_du_legacy)
|
||||
return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags,
|
||||
color, clips, num_clips);
|
||||
|
||||
return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color,
|
||||
clips, num_clips);
|
||||
}
|
||||
|
||||
static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = {
|
||||
.destroy = vmw_framebuffer_bo_destroy,
|
||||
.dirty = vmw_framebuffer_bo_dirty,
|
||||
.dirty = vmw_framebuffer_bo_dirty_ext,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1564,6 +1506,88 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_crtc_state_and_lock - Return new or current crtc state with locked
|
||||
* crtc mutex
|
||||
* @state: The atomic state pointer containing the new atomic state
|
||||
* @crtc: The crtc
|
||||
*
|
||||
* This function returns the new crtc state if it's part of the state update.
|
||||
* Otherwise returns the current crtc state. It also makes sure that the
|
||||
* crtc mutex is locked.
|
||||
*
|
||||
* Returns: A valid crtc state pointer or NULL. It may also return a
|
||||
* pointer error, in particular -EDEADLK if locking needs to be rerun.
|
||||
*/
|
||||
static struct drm_crtc_state *
|
||||
vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
if (crtc_state) {
|
||||
lockdep_assert_held(&crtc->mutex.mutex.base);
|
||||
} else {
|
||||
int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
|
||||
|
||||
if (ret != 0 && ret != -EALREADY)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
crtc_state = crtc->state;
|
||||
}
|
||||
|
||||
return crtc_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_check_implicit - Verify that all implicit display units scan out
|
||||
* from the same fb after the new state is committed.
|
||||
* @dev: The drm_device.
|
||||
* @state: The new state to be checked.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success,
|
||||
* -EINVAL on invalid state,
|
||||
* -EDEADLK if modeset locking needs to be rerun.
|
||||
*/
|
||||
static int vmw_kms_check_implicit(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_framebuffer *implicit_fb = NULL;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_plane_state *plane_state;
|
||||
|
||||
drm_for_each_crtc(crtc, dev) {
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
|
||||
if (!du->is_implicit)
|
||||
continue;
|
||||
|
||||
crtc_state = vmw_crtc_state_and_lock(state, crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
|
||||
if (!crtc_state || !crtc_state->enable)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Can't move primary planes across crtcs, so this is OK.
|
||||
* It also means we don't need to take the plane mutex.
|
||||
*/
|
||||
plane_state = du->primary.state;
|
||||
if (plane_state->crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (!implicit_fb)
|
||||
implicit_fb = plane_state->fb;
|
||||
else if (implicit_fb != plane_state->fb)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_check_topology - Validates topology in drm_atomic_state
|
||||
* @dev: DRM device
|
||||
@ -1575,7 +1599,6 @@ static int vmw_kms_check_display_memory(struct drm_device *dev,
|
||||
static int vmw_kms_check_topology(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(dev);
|
||||
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
||||
struct drm_rect *rects;
|
||||
struct drm_crtc *crtc;
|
||||
@ -1587,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev,
|
||||
if (!rects)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&dev_priv->requested_layout_mutex);
|
||||
|
||||
drm_for_each_crtc(crtc, dev) {
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
struct drm_crtc_state *crtc_state = crtc->state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
i = drm_crtc_index(crtc);
|
||||
|
||||
if (crtc_state && crtc_state->enable) {
|
||||
crtc_state = vmw_crtc_state_and_lock(state, crtc);
|
||||
if (IS_ERR(crtc_state)) {
|
||||
ret = PTR_ERR(crtc_state);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if (!crtc_state)
|
||||
continue;
|
||||
|
||||
if (crtc_state->enable) {
|
||||
rects[i].x1 = du->gui_x;
|
||||
rects[i].y1 = du->gui_y;
|
||||
rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay;
|
||||
rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay;
|
||||
} else {
|
||||
rects[i].x1 = 0;
|
||||
rects[i].y1 = 0;
|
||||
rects[i].x2 = 0;
|
||||
rects[i].y2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1611,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev,
|
||||
struct drm_connector_state *conn_state;
|
||||
struct vmw_connector_state *vmw_conn_state;
|
||||
|
||||
if (!new_crtc_state->enable) {
|
||||
rects[i].x1 = 0;
|
||||
rects[i].y1 = 0;
|
||||
rects[i].x2 = 0;
|
||||
rects[i].y2 = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!du->pref_active) {
|
||||
ret = -EINVAL;
|
||||
goto clean;
|
||||
@ -1639,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev,
|
||||
vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
|
||||
vmw_conn_state->gui_x = du->gui_x;
|
||||
vmw_conn_state->gui_y = du->gui_y;
|
||||
|
||||
rects[i].x1 = du->gui_x;
|
||||
rects[i].y1 = du->gui_y;
|
||||
rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay;
|
||||
rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay;
|
||||
}
|
||||
|
||||
ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc,
|
||||
rects);
|
||||
|
||||
clean:
|
||||
mutex_unlock(&dev_priv->requested_layout_mutex);
|
||||
kfree(rects);
|
||||
return ret;
|
||||
}
|
||||
@ -1681,6 +1702,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vmw_kms_check_implicit(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!state->allow_modeset)
|
||||
return ret;
|
||||
|
||||
@ -2003,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
|
||||
struct vmw_display_unit *du;
|
||||
struct drm_connector *con;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_crtc *crtc;
|
||||
int ret;
|
||||
|
||||
/* Currently gui_x/y is protected with the crtc mutex */
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
retry:
|
||||
drm_for_each_crtc(crtc, dev) {
|
||||
ret = drm_modeset_lock(&crtc->mutex, &ctx);
|
||||
if (ret < 0) {
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(&ctx);
|
||||
goto retry;
|
||||
}
|
||||
goto out_fini;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently only gui_x/y is protected with requested_layout_mutex.
|
||||
*/
|
||||
mutex_lock(&dev_priv->requested_layout_mutex);
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(con, &conn_iter) {
|
||||
du = vmw_connector_to_du(con);
|
||||
@ -2026,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
mutex_unlock(&dev_priv->requested_layout_mutex);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(con, &dev->mode_config.connector_list, head) {
|
||||
du = vmw_connector_to_du(con);
|
||||
if (num_rects > du->unit) {
|
||||
@ -2048,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
|
||||
}
|
||||
con->status = vmw_du_connector_detect(con, true);
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
drm_sysfs_hotplug_event(dev);
|
||||
|
||||
out_fini:
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2275,84 +2315,6 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vmw_du_connector_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct vmw_display_unit *du = vmw_connector_to_du(connector);
|
||||
struct vmw_private *dev_priv = vmw_priv(connector->dev);
|
||||
|
||||
if (property == dev_priv->implicit_placement_property)
|
||||
du->is_implicit = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_connector_atomic_set_property - Atomic version of get property
|
||||
*
|
||||
* @crtc - crtc the property is associated with
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
int
|
||||
vmw_du_connector_atomic_set_property(struct drm_connector *connector,
|
||||
struct drm_connector_state *state,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(connector->dev);
|
||||
struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state);
|
||||
struct vmw_display_unit *du = vmw_connector_to_du(connector);
|
||||
|
||||
|
||||
if (property == dev_priv->implicit_placement_property) {
|
||||
vcs->is_implicit = val;
|
||||
|
||||
/*
|
||||
* We should really be doing a drm_atomic_commit() to
|
||||
* commit the new state, but since this doesn't cause
|
||||
* an immedate state change, this is probably ok
|
||||
*/
|
||||
du->is_implicit = vcs->is_implicit;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_du_connector_atomic_get_property - Atomic version of get property
|
||||
*
|
||||
* @connector - connector the property is associated with
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
int
|
||||
vmw_du_connector_atomic_get_property(struct drm_connector *connector,
|
||||
const struct drm_connector_state *state,
|
||||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(connector->dev);
|
||||
struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state);
|
||||
|
||||
if (property == dev_priv->implicit_placement_property)
|
||||
*val = vcs->is_implicit;
|
||||
else {
|
||||
DRM_ERROR("Invalid Property %s\n", property->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl
|
||||
* @dev: drm device for the ioctl
|
||||
@ -2741,144 +2703,26 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer
|
||||
*
|
||||
* @dev_priv: Pointer to a device private struct.
|
||||
* @du: The display unit of the crtc.
|
||||
*/
|
||||
void vmw_kms_del_active(struct vmw_private *dev_priv,
|
||||
struct vmw_display_unit *du)
|
||||
{
|
||||
mutex_lock(&dev_priv->global_kms_state_mutex);
|
||||
if (du->active_implicit) {
|
||||
if (--(dev_priv->num_implicit) == 0)
|
||||
dev_priv->implicit_fb = NULL;
|
||||
du->active_implicit = false;
|
||||
}
|
||||
mutex_unlock(&dev_priv->global_kms_state_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_add_active - register a crtc binding to an implicit framebuffer
|
||||
*
|
||||
* @vmw_priv: Pointer to a device private struct.
|
||||
* @du: The display unit of the crtc.
|
||||
* @vfb: The implicit framebuffer
|
||||
*
|
||||
* Registers a binding to an implicit framebuffer.
|
||||
*/
|
||||
void vmw_kms_add_active(struct vmw_private *dev_priv,
|
||||
struct vmw_display_unit *du,
|
||||
struct vmw_framebuffer *vfb)
|
||||
{
|
||||
mutex_lock(&dev_priv->global_kms_state_mutex);
|
||||
WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb);
|
||||
|
||||
if (!du->active_implicit && du->is_implicit) {
|
||||
dev_priv->implicit_fb = vfb;
|
||||
du->active_implicit = true;
|
||||
dev_priv->num_implicit++;
|
||||
}
|
||||
mutex_unlock(&dev_priv->global_kms_state_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc.
|
||||
*
|
||||
* @dev_priv: Pointer to device-private struct.
|
||||
* @crtc: The crtc we want to flip.
|
||||
*
|
||||
* Returns true or false depending whether it's OK to flip this crtc
|
||||
* based on the criterion that we must not have more than one implicit
|
||||
* frame-buffer at any one time.
|
||||
*/
|
||||
bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
bool ret;
|
||||
|
||||
mutex_lock(&dev_priv->global_kms_state_mutex);
|
||||
ret = !du->is_implicit || dev_priv->num_implicit == 1;
|
||||
mutex_unlock(&dev_priv->global_kms_state_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_update_implicit_fb - Update the implicit fb.
|
||||
*
|
||||
* @dev_priv: Pointer to device-private struct.
|
||||
* @crtc: The crtc the new implicit frame-buffer is bound to.
|
||||
*/
|
||||
void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
struct vmw_framebuffer *vfb;
|
||||
|
||||
mutex_lock(&dev_priv->global_kms_state_mutex);
|
||||
|
||||
if (!du->is_implicit)
|
||||
goto out_unlock;
|
||||
|
||||
vfb = vmw_framebuffer_to_vfb(plane->state->fb);
|
||||
WARN_ON_ONCE(dev_priv->num_implicit != 1 &&
|
||||
dev_priv->implicit_fb != vfb);
|
||||
|
||||
dev_priv->implicit_fb = vfb;
|
||||
out_unlock:
|
||||
mutex_unlock(&dev_priv->global_kms_state_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_kms_create_implicit_placement_proparty - Set up the implicit placement
|
||||
* property.
|
||||
*
|
||||
* @dev_priv: Pointer to a device private struct.
|
||||
* @immutable: Whether the property is immutable.
|
||||
*
|
||||
* Sets up the implicit placement property unless it's already set up.
|
||||
*/
|
||||
void
|
||||
vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv,
|
||||
bool immutable)
|
||||
vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv)
|
||||
{
|
||||
if (dev_priv->implicit_placement_property)
|
||||
return;
|
||||
|
||||
dev_priv->implicit_placement_property =
|
||||
drm_property_create_range(dev_priv->dev,
|
||||
immutable ?
|
||||
DRM_MODE_PROP_IMMUTABLE : 0,
|
||||
DRM_MODE_PROP_IMMUTABLE,
|
||||
"implicit_placement", 0, 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config
|
||||
*
|
||||
* @set: The configuration to set.
|
||||
*
|
||||
* The vmwgfx Xorg driver doesn't assign the mode::type member, which
|
||||
* when drm_mode_set_crtcinfo is called as part of the configuration setting
|
||||
* causes it to return incorrect crtc dimensions causing severe problems in
|
||||
* the vmwgfx modesetting. So explicitly clear that member before calling
|
||||
* into drm_atomic_helper_set_config.
|
||||
*/
|
||||
int vmw_kms_set_config(struct drm_mode_set *set,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
if (set && set->mode)
|
||||
set->mode->type = 0;
|
||||
|
||||
return drm_atomic_helper_set_config(set, ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_kms_suspend - Save modesetting state and turn modesetting off.
|
||||
*
|
||||
@ -2935,3 +2779,124 @@ void vmw_kms_lost_device(struct drm_device *dev)
|
||||
{
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_du_helper_plane_update - Helper to do plane update on a display unit.
|
||||
* @update: The closure structure.
|
||||
*
|
||||
* Call this helper after setting callbacks in &vmw_du_update_plane to do plane
|
||||
* update on display unit.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
|
||||
{
|
||||
struct drm_plane_state *state = update->plane->state;
|
||||
struct drm_plane_state *old_state = update->old_state;
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_rect clip;
|
||||
struct drm_rect bb;
|
||||
DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
|
||||
uint32_t reserved_size = 0;
|
||||
uint32_t submit_size = 0;
|
||||
uint32_t curr_size = 0;
|
||||
uint32_t num_hits = 0;
|
||||
void *cmd_start;
|
||||
char *cmd_next;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Iterate in advance to check if really need plane update and find the
|
||||
* number of clips that actually are in plane src for fifo allocation.
|
||||
*/
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_state, state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip)
|
||||
num_hits++;
|
||||
|
||||
if (num_hits == 0)
|
||||
return 0;
|
||||
|
||||
if (update->vfb->bo) {
|
||||
struct vmw_framebuffer_bo *vfbbo =
|
||||
container_of(update->vfb, typeof(*vfbbo), base);
|
||||
|
||||
ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false,
|
||||
update->cpu_blit);
|
||||
} else {
|
||||
struct vmw_framebuffer_surface *vfbs =
|
||||
container_of(update->vfb, typeof(*vfbs), base);
|
||||
|
||||
ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res,
|
||||
0, NULL, NULL);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr);
|
||||
if (ret)
|
||||
goto out_unref;
|
||||
|
||||
reserved_size = update->calc_fifo_size(update, num_hits);
|
||||
cmd_start = vmw_fifo_reserve(update->dev_priv, reserved_size);
|
||||
if (!cmd_start) {
|
||||
ret = -ENOMEM;
|
||||
goto out_revert;
|
||||
}
|
||||
|
||||
cmd_next = cmd_start;
|
||||
|
||||
if (update->post_prepare) {
|
||||
curr_size = update->post_prepare(update, cmd_next);
|
||||
cmd_next += curr_size;
|
||||
submit_size += curr_size;
|
||||
}
|
||||
|
||||
if (update->pre_clip) {
|
||||
curr_size = update->pre_clip(update, cmd_next, num_hits);
|
||||
cmd_next += curr_size;
|
||||
submit_size += curr_size;
|
||||
}
|
||||
|
||||
bb.x1 = INT_MAX;
|
||||
bb.y1 = INT_MAX;
|
||||
bb.x2 = INT_MIN;
|
||||
bb.y2 = INT_MIN;
|
||||
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_state, state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip) {
|
||||
uint32_t fb_x = clip.x1;
|
||||
uint32_t fb_y = clip.y1;
|
||||
|
||||
vmw_du_translate_to_crtc(state, &clip);
|
||||
if (update->clip) {
|
||||
curr_size = update->clip(update, cmd_next, &clip, fb_x,
|
||||
fb_y);
|
||||
cmd_next += curr_size;
|
||||
submit_size += curr_size;
|
||||
}
|
||||
bb.x1 = min_t(int, bb.x1, clip.x1);
|
||||
bb.y1 = min_t(int, bb.y1, clip.y1);
|
||||
bb.x2 = max_t(int, bb.x2, clip.x2);
|
||||
bb.y2 = max_t(int, bb.y2, clip.y2);
|
||||
}
|
||||
|
||||
curr_size = update->post_clip(update, cmd_next, &bb);
|
||||
submit_size += curr_size;
|
||||
|
||||
if (reserved_size < submit_size)
|
||||
submit_size = 0;
|
||||
|
||||
vmw_fifo_commit(update->dev_priv, submit_size);
|
||||
|
||||
vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx,
|
||||
update->out_fence, NULL);
|
||||
return ret;
|
||||
|
||||
out_revert:
|
||||
vmw_validation_revert(&val_ctx);
|
||||
|
||||
out_unref:
|
||||
vmw_validation_unref_lists(&val_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
@ -33,7 +33,123 @@
|
||||
#include <drm/drm_encoder.h>
|
||||
#include "vmwgfx_drv.h"
|
||||
|
||||
/**
|
||||
* struct vmw_du_update_plane - Closure structure for vmw_du_helper_plane_update
|
||||
* @plane: Plane which is being updated.
|
||||
* @old_state: Old state of plane.
|
||||
* @dev_priv: Device private.
|
||||
* @du: Display unit on which to update the plane.
|
||||
* @vfb: Framebuffer which is blitted to display unit.
|
||||
* @out_fence: Out fence for resource finish.
|
||||
* @mutex: The mutex used to protect resource reservation.
|
||||
* @cpu_blit: True if need cpu blit.
|
||||
* @intr: Whether to perform waits interruptible if possible.
|
||||
*
|
||||
* This structure loosely represent the set of operations needed to perform a
|
||||
* plane update on a display unit. Implementer will define that functionality
|
||||
* according to the function callbacks for this structure. In brief it involves
|
||||
* surface/buffer object validation, populate FIFO commands and command
|
||||
* submission to the device.
|
||||
*/
|
||||
struct vmw_du_update_plane {
|
||||
/**
|
||||
* @calc_fifo_size: Calculate fifo size.
|
||||
*
|
||||
* Determine fifo size for the commands needed for update. The number of
|
||||
* damage clips on display unit @num_hits will be passed to allocate
|
||||
* sufficient fifo space.
|
||||
*
|
||||
* Return: Fifo size needed
|
||||
*/
|
||||
uint32_t (*calc_fifo_size)(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits);
|
||||
|
||||
/**
|
||||
* @post_prepare: Populate fifo for resource preparation.
|
||||
*
|
||||
* Some surface resource or buffer object need some extra cmd submission
|
||||
* like update GB image for proxy surface and define a GMRFB for screen
|
||||
* object. That should should be done here as this callback will be
|
||||
* called after FIFO allocation with the address of command buufer.
|
||||
*
|
||||
* This callback is optional.
|
||||
*
|
||||
* Return: Size of commands populated to command buffer.
|
||||
*/
|
||||
uint32_t (*post_prepare)(struct vmw_du_update_plane *update, void *cmd);
|
||||
|
||||
/**
|
||||
* @pre_clip: Populate fifo before clip.
|
||||
*
|
||||
* This is where pre clip related command should be populated like
|
||||
* surface copy/DMA, etc.
|
||||
*
|
||||
* This callback is optional.
|
||||
*
|
||||
* Return: Size of commands populated to command buffer.
|
||||
*/
|
||||
uint32_t (*pre_clip)(struct vmw_du_update_plane *update, void *cmd,
|
||||
uint32_t num_hits);
|
||||
|
||||
/**
|
||||
* @clip: Populate fifo for clip.
|
||||
*
|
||||
* This is where to populate clips for surface copy/dma or blit commands
|
||||
* if needed. This will be called times have damage in display unit,
|
||||
* which is one if doing full update. @clip is the damage in destination
|
||||
* coordinates which is crtc/DU and @src_x, @src_y is damage clip src in
|
||||
* framebuffer coordinate.
|
||||
*
|
||||
* This callback is optional.
|
||||
*
|
||||
* Return: Size of commands populated to command buffer.
|
||||
*/
|
||||
uint32_t (*clip)(struct vmw_du_update_plane *update, void *cmd,
|
||||
struct drm_rect *clip, uint32_t src_x, uint32_t src_y);
|
||||
|
||||
/**
|
||||
* @post_clip: Populate fifo after clip.
|
||||
*
|
||||
* This is where to populate display unit update commands or blit
|
||||
* commands.
|
||||
*
|
||||
* Return: Size of commands populated to command buffer.
|
||||
*/
|
||||
uint32_t (*post_clip)(struct vmw_du_update_plane *update, void *cmd,
|
||||
struct drm_rect *bb);
|
||||
|
||||
struct drm_plane *plane;
|
||||
struct drm_plane_state *old_state;
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_display_unit *du;
|
||||
struct vmw_framebuffer *vfb;
|
||||
struct vmw_fence_obj **out_fence;
|
||||
struct mutex *mutex;
|
||||
bool cpu_blit;
|
||||
bool intr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vmw_du_update_plane_surface - closure structure for surface
|
||||
* @base: base closure structure.
|
||||
* @cmd_start: FIFO command start address (used by SOU only).
|
||||
*/
|
||||
struct vmw_du_update_plane_surface {
|
||||
struct vmw_du_update_plane base;
|
||||
/* This member is to handle special case SOU surface update */
|
||||
void *cmd_start;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vmw_du_update_plane_buffer - Closure structure for buffer object
|
||||
* @base: Base closure structure.
|
||||
* @fb_left: x1 for fb damage bounding box.
|
||||
* @fb_top: y1 for fb damage bounding box.
|
||||
*/
|
||||
struct vmw_du_update_plane_buffer {
|
||||
struct vmw_du_update_plane base;
|
||||
int fb_left, fb_top;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty
|
||||
@ -191,8 +307,6 @@ struct vmw_plane_state {
|
||||
struct vmw_connector_state {
|
||||
struct drm_connector_state base;
|
||||
|
||||
bool is_implicit;
|
||||
|
||||
/**
|
||||
* @gui_x:
|
||||
*
|
||||
@ -254,7 +368,6 @@ struct vmw_display_unit {
|
||||
int gui_x;
|
||||
int gui_y;
|
||||
bool is_implicit;
|
||||
bool active_implicit;
|
||||
int set_gui_x;
|
||||
int set_gui_y;
|
||||
};
|
||||
@ -334,17 +447,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
|
||||
struct drm_crtc **p_crtc,
|
||||
struct drm_display_mode **p_mode);
|
||||
void vmw_guess_mode_timing(struct drm_display_mode *mode);
|
||||
void vmw_kms_del_active(struct vmw_private *dev_priv,
|
||||
struct vmw_display_unit *du);
|
||||
void vmw_kms_add_active(struct vmw_private *dev_priv,
|
||||
struct vmw_display_unit *du,
|
||||
struct vmw_framebuffer *vfb);
|
||||
bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv,
|
||||
struct drm_crtc *crtc);
|
||||
void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv,
|
||||
struct drm_crtc *crtc);
|
||||
void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv,
|
||||
bool immutable);
|
||||
void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv);
|
||||
void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
|
||||
|
||||
/* Universal Plane Helpers */
|
||||
void vmw_du_primary_plane_destroy(struct drm_plane *plane);
|
||||
@ -456,6 +560,20 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
|
||||
bool interruptible,
|
||||
struct drm_crtc *crtc);
|
||||
|
||||
int vmw_kms_set_config(struct drm_mode_set *set,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
int vmw_du_helper_plane_update(struct vmw_du_update_plane *update);
|
||||
|
||||
/**
|
||||
* vmw_du_translate_to_crtc - Translate a rect from framebuffer to crtc
|
||||
* @state: Plane state.
|
||||
* @r: Rectangle to translate.
|
||||
*/
|
||||
static inline void vmw_du_translate_to_crtc(struct drm_plane_state *state,
|
||||
struct drm_rect *r)
|
||||
{
|
||||
int translate_crtc_x = -((state->src_x >> 16) - state->crtc_x);
|
||||
int translate_crtc_y = -((state->src_y >> 16) - state->crtc_y);
|
||||
|
||||
drm_rect_translate(r, translate_crtc_x, translate_crtc_y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -233,7 +233,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
|
||||
.reset = vmw_du_crtc_reset,
|
||||
.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
|
||||
.atomic_destroy_state = vmw_du_crtc_destroy_state,
|
||||
.set_config = vmw_kms_set_config,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
};
|
||||
|
||||
|
||||
@ -263,13 +263,10 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
|
||||
.dpms = vmw_du_connector_dpms,
|
||||
.detect = vmw_du_connector_detect,
|
||||
.fill_modes = vmw_du_connector_fill_modes,
|
||||
.set_property = vmw_du_connector_set_property,
|
||||
.destroy = vmw_ldu_connector_destroy,
|
||||
.reset = vmw_du_connector_reset,
|
||||
.atomic_duplicate_state = vmw_du_connector_duplicate_state,
|
||||
.atomic_destroy_state = vmw_du_connector_destroy_state,
|
||||
.atomic_set_property = vmw_du_connector_atomic_set_property,
|
||||
.atomic_get_property = vmw_du_connector_atomic_get_property,
|
||||
};
|
||||
|
||||
static const struct
|
||||
@ -416,7 +413,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
|
||||
drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
|
||||
|
||||
|
||||
vmw_du_connector_reset(connector);
|
||||
ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_VIRTUAL);
|
||||
@ -427,8 +423,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
|
||||
drm_connector_helper_add(connector, &vmw_ldu_connector_helper_funcs);
|
||||
connector->status = vmw_du_connector_detect(connector, true);
|
||||
vmw_connector_state_to_vcs(connector->state)->is_implicit = true;
|
||||
|
||||
|
||||
ret = drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
|
||||
DRM_MODE_ENCODER_VIRTUAL, NULL);
|
||||
@ -447,7 +441,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
goto err_free_encoder;
|
||||
}
|
||||
|
||||
|
||||
vmw_du_crtc_reset(crtc);
|
||||
ret = drm_crtc_init_with_planes(dev, crtc, &ldu->base.primary,
|
||||
&ldu->base.cursor,
|
||||
@ -513,7 +506,7 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
|
||||
if (ret != 0)
|
||||
goto err_free;
|
||||
|
||||
vmw_kms_create_implicit_placement_property(dev_priv, true);
|
||||
vmw_kms_create_implicit_placement_property(dev_priv);
|
||||
|
||||
if (dev_priv->capabilities & SVGA_CAP_MULTIMON)
|
||||
for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
|
||||
|
||||
#define vmw_crtc_to_sou(x) \
|
||||
@ -76,6 +77,11 @@ struct vmw_kms_sou_dirty_cmd {
|
||||
SVGA3dCmdBlitSurfaceToScreen body;
|
||||
};
|
||||
|
||||
struct vmw_kms_sou_define_gmrfb {
|
||||
uint32_t header;
|
||||
SVGAFifoCmdDefineGMRFB body;
|
||||
};
|
||||
|
||||
/**
|
||||
* Display unit using screen objects.
|
||||
*/
|
||||
@ -241,28 +247,20 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
sou->buffer = vps->bo;
|
||||
sou->buffer_size = vps->bo_size;
|
||||
|
||||
if (sou->base.is_implicit) {
|
||||
x = crtc->x;
|
||||
y = crtc->y;
|
||||
} else {
|
||||
conn_state = sou->base.connector.state;
|
||||
vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
|
||||
conn_state = sou->base.connector.state;
|
||||
vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
|
||||
|
||||
x = vmw_conn_state->gui_x;
|
||||
y = vmw_conn_state->gui_y;
|
||||
}
|
||||
x = vmw_conn_state->gui_x;
|
||||
y = vmw_conn_state->gui_y;
|
||||
|
||||
ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to define Screen Object %dx%d\n",
|
||||
crtc->x, crtc->y);
|
||||
|
||||
vmw_kms_add_active(dev_priv, &sou->base, vfb);
|
||||
} else {
|
||||
sou->buffer = NULL;
|
||||
sou->buffer_size = 0;
|
||||
|
||||
vmw_kms_del_active(dev_priv, &sou->base);
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,38 +315,14 @@ static void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
}
|
||||
}
|
||||
|
||||
static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *new_fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t flags,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
int ret;
|
||||
|
||||
if (!vmw_kms_crtc_flippable(dev_priv, crtc))
|
||||
return -EINVAL;
|
||||
|
||||
ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
|
||||
if (ret) {
|
||||
DRM_ERROR("Page flip error %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vmw_crtc_to_du(crtc)->is_implicit)
|
||||
vmw_kms_update_implicit_fb(dev_priv, crtc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
|
||||
.gamma_set = vmw_du_crtc_gamma_set,
|
||||
.destroy = vmw_sou_crtc_destroy,
|
||||
.reset = vmw_du_crtc_reset,
|
||||
.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
|
||||
.atomic_destroy_state = vmw_du_crtc_destroy_state,
|
||||
.set_config = vmw_kms_set_config,
|
||||
.page_flip = vmw_sou_crtc_page_flip,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -377,13 +351,10 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = {
|
||||
.dpms = vmw_du_connector_dpms,
|
||||
.detect = vmw_du_connector_detect,
|
||||
.fill_modes = vmw_du_connector_fill_modes,
|
||||
.set_property = vmw_du_connector_set_property,
|
||||
.destroy = vmw_sou_connector_destroy,
|
||||
.reset = vmw_du_connector_reset,
|
||||
.atomic_duplicate_state = vmw_du_connector_duplicate_state,
|
||||
.atomic_destroy_state = vmw_du_connector_destroy_state,
|
||||
.atomic_set_property = vmw_du_connector_atomic_set_property,
|
||||
.atomic_get_property = vmw_du_connector_atomic_get_property,
|
||||
};
|
||||
|
||||
|
||||
@ -498,6 +469,263 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
|
||||
return vmw_bo_pin_in_vram(dev_priv, vps->bo, true);
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
return sizeof(struct vmw_kms_sou_define_gmrfb) +
|
||||
sizeof(struct vmw_kms_sou_bo_blit) * num_hits;
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update,
|
||||
void *cmd)
|
||||
{
|
||||
struct vmw_framebuffer_bo *vfbbo =
|
||||
container_of(update->vfb, typeof(*vfbbo), base);
|
||||
struct vmw_kms_sou_define_gmrfb *gmr = cmd;
|
||||
int depth = update->vfb->base.format->depth;
|
||||
|
||||
/* Emulate RGBA support, contrary to svga_reg.h this is not
|
||||
* supported by hosts. This is only a problem if we are reading
|
||||
* this value later and expecting what we uploaded back.
|
||||
*/
|
||||
if (depth == 32)
|
||||
depth = 24;
|
||||
|
||||
gmr->header = SVGA_CMD_DEFINE_GMRFB;
|
||||
|
||||
gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8;
|
||||
gmr->body.format.colorDepth = depth;
|
||||
gmr->body.format.reserved = 0;
|
||||
gmr->body.bytesPerLine = update->vfb->base.pitches[0];
|
||||
vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr);
|
||||
|
||||
return sizeof(*gmr);
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *clip,
|
||||
uint32_t fb_x, uint32_t fb_y)
|
||||
{
|
||||
struct vmw_kms_sou_bo_blit *blit = cmd;
|
||||
|
||||
blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
|
||||
blit->body.destScreenId = update->du->unit;
|
||||
blit->body.srcOrigin.x = fb_x;
|
||||
blit->body.srcOrigin.y = fb_y;
|
||||
blit->body.destRect.left = clip->x1;
|
||||
blit->body.destRect.top = clip->y1;
|
||||
blit->body.destRect.right = clip->x2;
|
||||
blit->body.destRect.bottom = clip->y2;
|
||||
|
||||
return sizeof(*blit);
|
||||
}
|
||||
|
||||
static uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *bb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_sou_plane_update_bo - Update display unit for bo backed fb.
|
||||
* @dev_priv: Device private.
|
||||
* @plane: Plane state.
|
||||
* @old_state: Old plane state.
|
||||
* @vfb: Framebuffer which is blitted to display unit.
|
||||
* @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
|
||||
* The returned fence pointer may be NULL in which case the device
|
||||
* has already synchronized.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
static int vmw_sou_plane_update_bo(struct vmw_private *dev_priv,
|
||||
struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state,
|
||||
struct vmw_framebuffer *vfb,
|
||||
struct vmw_fence_obj **out_fence)
|
||||
{
|
||||
struct vmw_du_update_plane_buffer bo_update;
|
||||
|
||||
memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
|
||||
bo_update.base.plane = plane;
|
||||
bo_update.base.old_state = old_state;
|
||||
bo_update.base.dev_priv = dev_priv;
|
||||
bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
|
||||
bo_update.base.vfb = vfb;
|
||||
bo_update.base.out_fence = out_fence;
|
||||
bo_update.base.mutex = NULL;
|
||||
bo_update.base.cpu_blit = false;
|
||||
bo_update.base.intr = true;
|
||||
|
||||
bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size;
|
||||
bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb;
|
||||
bo_update.base.clip = vmw_sou_bo_populate_clip;
|
||||
bo_update.base.post_clip = vmw_stud_bo_post_clip;
|
||||
|
||||
return vmw_du_helper_plane_update(&bo_update.base);
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) *
|
||||
num_hits;
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update,
|
||||
void *cmd)
|
||||
{
|
||||
struct vmw_du_update_plane_surface *srf_update;
|
||||
|
||||
srf_update = container_of(update, typeof(*srf_update), base);
|
||||
|
||||
/*
|
||||
* SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that
|
||||
* its bounding box is filled before iterating over all the clips. So
|
||||
* store the FIFO start address and revisit to fill the details.
|
||||
*/
|
||||
srf_update->cmd_start = cmd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update,
|
||||
void *cmd, uint32_t num_hits)
|
||||
{
|
||||
struct vmw_kms_sou_dirty_cmd *blit = cmd;
|
||||
struct vmw_framebuffer_surface *vfbs;
|
||||
|
||||
vfbs = container_of(update->vfb, typeof(*vfbs), base);
|
||||
|
||||
blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
|
||||
blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) *
|
||||
num_hits;
|
||||
|
||||
blit->body.srcImage.sid = vfbs->surface->res.id;
|
||||
blit->body.destScreenId = update->du->unit;
|
||||
|
||||
/* Update the source and destination bounding box later in post_clip */
|
||||
blit->body.srcRect.left = 0;
|
||||
blit->body.srcRect.top = 0;
|
||||
blit->body.srcRect.right = 0;
|
||||
blit->body.srcRect.bottom = 0;
|
||||
|
||||
blit->body.destRect.left = 0;
|
||||
blit->body.destRect.top = 0;
|
||||
blit->body.destRect.right = 0;
|
||||
blit->body.destRect.bottom = 0;
|
||||
|
||||
return sizeof(*blit);
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *clip,
|
||||
uint32_t src_x, uint32_t src_y)
|
||||
{
|
||||
SVGASignedRect *rect = cmd;
|
||||
|
||||
/*
|
||||
* rects are relative to dest bounding box rect on screen object, so
|
||||
* translate to it later in post_clip
|
||||
*/
|
||||
rect->left = clip->x1;
|
||||
rect->top = clip->y1;
|
||||
rect->right = clip->x2;
|
||||
rect->bottom = clip->y2;
|
||||
|
||||
return sizeof(*rect);
|
||||
}
|
||||
|
||||
static uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *bb)
|
||||
{
|
||||
struct vmw_du_update_plane_surface *srf_update;
|
||||
struct drm_plane_state *state = update->plane->state;
|
||||
struct drm_rect src_bb;
|
||||
struct vmw_kms_sou_dirty_cmd *blit;
|
||||
SVGASignedRect *rect;
|
||||
uint32_t num_hits;
|
||||
int translate_src_x;
|
||||
int translate_src_y;
|
||||
int i;
|
||||
|
||||
srf_update = container_of(update, typeof(*srf_update), base);
|
||||
|
||||
blit = srf_update->cmd_start;
|
||||
rect = (SVGASignedRect *)&blit[1];
|
||||
|
||||
num_hits = (blit->header.size - sizeof(blit->body))/
|
||||
sizeof(SVGASignedRect);
|
||||
|
||||
src_bb = *bb;
|
||||
|
||||
/* To translate bb back to fb src coord */
|
||||
translate_src_x = (state->src_x >> 16) - state->crtc_x;
|
||||
translate_src_y = (state->src_y >> 16) - state->crtc_y;
|
||||
|
||||
drm_rect_translate(&src_bb, translate_src_x, translate_src_y);
|
||||
|
||||
blit->body.srcRect.left = src_bb.x1;
|
||||
blit->body.srcRect.top = src_bb.y1;
|
||||
blit->body.srcRect.right = src_bb.x2;
|
||||
blit->body.srcRect.bottom = src_bb.y2;
|
||||
|
||||
blit->body.destRect.left = bb->x1;
|
||||
blit->body.destRect.top = bb->y1;
|
||||
blit->body.destRect.right = bb->x2;
|
||||
blit->body.destRect.bottom = bb->y2;
|
||||
|
||||
/* rects are relative to dest bb rect */
|
||||
for (i = 0; i < num_hits; i++) {
|
||||
rect->left -= bb->x1;
|
||||
rect->top -= bb->y1;
|
||||
rect->right -= bb->x1;
|
||||
rect->bottom -= bb->y1;
|
||||
rect++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_sou_plane_update_surface - Update display unit for surface backed fb.
|
||||
* @dev_priv: Device private.
|
||||
* @plane: Plane state.
|
||||
* @old_state: Old plane state.
|
||||
* @vfb: Framebuffer which is blitted to display unit
|
||||
* @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
|
||||
* The returned fence pointer may be NULL in which case the device
|
||||
* has already synchronized.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
static int vmw_sou_plane_update_surface(struct vmw_private *dev_priv,
|
||||
struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state,
|
||||
struct vmw_framebuffer *vfb,
|
||||
struct vmw_fence_obj **out_fence)
|
||||
{
|
||||
struct vmw_du_update_plane_surface srf_update;
|
||||
|
||||
memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface));
|
||||
srf_update.base.plane = plane;
|
||||
srf_update.base.old_state = old_state;
|
||||
srf_update.base.dev_priv = dev_priv;
|
||||
srf_update.base.du = vmw_crtc_to_du(plane->state->crtc);
|
||||
srf_update.base.vfb = vfb;
|
||||
srf_update.base.out_fence = out_fence;
|
||||
srf_update.base.mutex = &dev_priv->cmdbuf_mutex;
|
||||
srf_update.base.cpu_blit = false;
|
||||
srf_update.base.intr = true;
|
||||
|
||||
srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size;
|
||||
srf_update.base.post_prepare = vmw_sou_surface_post_prepare;
|
||||
srf_update.base.pre_clip = vmw_sou_surface_pre_clip;
|
||||
srf_update.base.clip = vmw_sou_surface_clip_rect;
|
||||
srf_update.base.post_clip = vmw_sou_surface_post_clip;
|
||||
|
||||
return vmw_du_helper_plane_update(&srf_update.base);
|
||||
}
|
||||
|
||||
static void
|
||||
vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
@ -508,47 +736,28 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct vmw_fence_obj *fence = NULL;
|
||||
int ret;
|
||||
|
||||
/* In case of device error, maintain consistent atomic state */
|
||||
if (crtc && plane->state->fb) {
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
struct vmw_framebuffer *vfb =
|
||||
vmw_framebuffer_to_vfb(plane->state->fb);
|
||||
struct drm_vmw_rect vclips;
|
||||
|
||||
vclips.x = crtc->x;
|
||||
vclips.y = crtc->y;
|
||||
vclips.w = crtc->mode.hdisplay;
|
||||
vclips.h = crtc->mode.vdisplay;
|
||||
|
||||
if (vfb->bo)
|
||||
ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL,
|
||||
&vclips, 1, 1, true,
|
||||
&fence, crtc);
|
||||
ret = vmw_sou_plane_update_bo(dev_priv, plane,
|
||||
old_state, vfb, &fence);
|
||||
else
|
||||
ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL,
|
||||
&vclips, NULL, 0, 0,
|
||||
1, 1, &fence, crtc);
|
||||
|
||||
/*
|
||||
* We cannot really fail this function, so if we do, then output
|
||||
* an error and maintain consistent atomic state.
|
||||
*/
|
||||
ret = vmw_sou_plane_update_surface(dev_priv, plane,
|
||||
old_state, vfb,
|
||||
&fence);
|
||||
if (ret != 0)
|
||||
DRM_ERROR("Failed to update screen.\n");
|
||||
} else {
|
||||
/*
|
||||
* When disabling a plane, CRTC and FB should always be NULL
|
||||
* together, otherwise it's an error.
|
||||
* Here primary plane is being disable so should really blank
|
||||
* the screen object display unit, if not already done.
|
||||
*/
|
||||
/* Do nothing when fb and crtc is NULL (blank crtc) */
|
||||
return;
|
||||
}
|
||||
|
||||
/* For error case vblank event is send from vmw_du_crtc_atomic_flush */
|
||||
event = crtc->state->event;
|
||||
/*
|
||||
* In case of failure and other cases, vblank event will be sent in
|
||||
* vmw_du_crtc_atomic_flush.
|
||||
*/
|
||||
if (event && fence) {
|
||||
struct drm_file *file_priv = event->base.file_priv;
|
||||
|
||||
@ -639,7 +848,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
primary = &sou->base.primary;
|
||||
cursor = &sou->base.cursor;
|
||||
|
||||
sou->base.active_implicit = false;
|
||||
sou->base.pref_active = (unit == 0);
|
||||
sou->base.pref_width = dev_priv->initial_width;
|
||||
sou->base.pref_height = dev_priv->initial_height;
|
||||
@ -665,6 +873,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
}
|
||||
|
||||
drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
|
||||
drm_plane_enable_fb_damage_clips(primary);
|
||||
|
||||
/* Initialize cursor plane */
|
||||
vmw_du_plane_reset(cursor);
|
||||
@ -692,8 +901,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
|
||||
drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs);
|
||||
connector->status = vmw_du_connector_detect(connector, true);
|
||||
vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
|
||||
|
||||
|
||||
ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
|
||||
DRM_MODE_ENCODER_VIRTUAL, NULL);
|
||||
@ -732,12 +939,6 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
dev->mode_config.suggested_x_property, 0);
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.suggested_y_property, 0);
|
||||
if (dev_priv->implicit_placement_property)
|
||||
drm_object_attach_property
|
||||
(&connector->base,
|
||||
dev_priv->implicit_placement_property,
|
||||
sou->base.is_implicit);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_unregister:
|
||||
@ -763,15 +964,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
dev_priv->num_implicit = 0;
|
||||
dev_priv->implicit_fb = NULL;
|
||||
|
||||
ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
|
||||
if (unlikely(ret != 0))
|
||||
return ret;
|
||||
|
||||
vmw_kms_create_implicit_placement_property(dev_priv, false);
|
||||
|
||||
for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
|
||||
vmw_sou_init(dev_priv, i);
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
|
||||
#define vmw_crtc_to_stdu(x) \
|
||||
container_of(x, struct vmw_screen_target_display_unit, base.crtc)
|
||||
@ -92,6 +92,10 @@ struct vmw_stdu_surface_copy {
|
||||
SVGA3dCmdSurfaceCopy body;
|
||||
};
|
||||
|
||||
struct vmw_stdu_update_gb_image {
|
||||
SVGA3dCmdHeader header;
|
||||
SVGA3dCmdUpdateGBImage body;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vmw_screen_target_display_unit
|
||||
@ -396,13 +400,8 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
if (!crtc->state->enable)
|
||||
return;
|
||||
|
||||
if (stdu->base.is_implicit) {
|
||||
x = crtc->x;
|
||||
y = crtc->y;
|
||||
} else {
|
||||
x = vmw_conn_state->gui_x;
|
||||
y = vmw_conn_state->gui_y;
|
||||
}
|
||||
x = vmw_conn_state->gui_x;
|
||||
y = vmw_conn_state->gui_y;
|
||||
|
||||
vmw_svga_enable(dev_priv);
|
||||
ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y);
|
||||
@ -417,27 +416,9 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
struct drm_plane_state *plane_state = crtc->primary->state;
|
||||
struct vmw_private *dev_priv;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer *vfb;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
fb = plane_state->fb;
|
||||
|
||||
vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
|
||||
|
||||
if (vfb)
|
||||
vmw_kms_add_active(dev_priv, &stdu->base, vfb);
|
||||
else
|
||||
vmw_kms_del_active(dev_priv, &stdu->base);
|
||||
}
|
||||
|
||||
static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
@ -471,49 +452,6 @@ static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_stdu_crtc_page_flip - Binds a buffer to a screen target
|
||||
*
|
||||
* @crtc: CRTC to attach FB to
|
||||
* @fb: FB to attach
|
||||
* @event: Event to be posted. This event should've been alloced
|
||||
* using k[mz]alloc, and should've been completely initialized.
|
||||
* @page_flip_flags: Input flags.
|
||||
*
|
||||
* If the STDU uses the same display and content buffers, i.e. a true flip,
|
||||
* this function will replace the existing display buffer with the new content
|
||||
* buffer.
|
||||
*
|
||||
* If the STDU uses different display and content buffers, i.e. a blit, then
|
||||
* only the content buffer will be updated.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, error code on failure
|
||||
*/
|
||||
static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *new_fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t flags,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
|
||||
{
|
||||
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
|
||||
struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
|
||||
int ret;
|
||||
|
||||
if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc))
|
||||
return -EINVAL;
|
||||
|
||||
ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
|
||||
if (ret) {
|
||||
DRM_ERROR("Page flip error %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect
|
||||
*
|
||||
@ -986,8 +924,8 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
|
||||
.reset = vmw_du_crtc_reset,
|
||||
.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
|
||||
.atomic_destroy_state = vmw_du_crtc_destroy_state,
|
||||
.set_config = vmw_kms_set_config,
|
||||
.page_flip = vmw_stdu_crtc_page_flip,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
};
|
||||
|
||||
|
||||
@ -1042,13 +980,10 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
|
||||
.dpms = vmw_du_connector_dpms,
|
||||
.detect = vmw_du_connector_detect,
|
||||
.fill_modes = vmw_du_connector_fill_modes,
|
||||
.set_property = vmw_du_connector_set_property,
|
||||
.destroy = vmw_stdu_connector_destroy,
|
||||
.reset = vmw_du_connector_reset,
|
||||
.atomic_duplicate_state = vmw_du_connector_duplicate_state,
|
||||
.atomic_destroy_state = vmw_du_connector_destroy_state,
|
||||
.atomic_set_property = vmw_du_connector_atomic_set_property,
|
||||
.atomic_get_property = vmw_du_connector_atomic_get_property,
|
||||
};
|
||||
|
||||
|
||||
@ -1256,11 +1191,402 @@ out_srf_unref:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits +
|
||||
sizeof(SVGA3dCmdSurfaceDMASuffix) +
|
||||
sizeof(struct vmw_stdu_update);
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
return sizeof(struct vmw_stdu_update_gb_image) +
|
||||
sizeof(struct vmw_stdu_update);
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update,
|
||||
void *cmd, uint32_t num_hits)
|
||||
{
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer_bo *vfbbo;
|
||||
struct vmw_stdu_dma *cmd_dma = cmd;
|
||||
|
||||
stdu = container_of(update->du, typeof(*stdu), base);
|
||||
vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
|
||||
|
||||
cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA;
|
||||
cmd_dma->header.size = sizeof(cmd_dma->body) +
|
||||
sizeof(struct SVGA3dCopyBox) * num_hits +
|
||||
sizeof(SVGA3dCmdSurfaceDMASuffix);
|
||||
vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr);
|
||||
cmd_dma->body.guest.pitch = update->vfb->base.pitches[0];
|
||||
cmd_dma->body.host.sid = stdu->display_srf->res.id;
|
||||
cmd_dma->body.host.face = 0;
|
||||
cmd_dma->body.host.mipmap = 0;
|
||||
cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM;
|
||||
|
||||
return sizeof(*cmd_dma);
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *clip,
|
||||
uint32_t fb_x, uint32_t fb_y)
|
||||
{
|
||||
struct SVGA3dCopyBox *box = cmd;
|
||||
|
||||
box->srcx = fb_x;
|
||||
box->srcy = fb_y;
|
||||
box->srcz = 0;
|
||||
box->x = clip->x1;
|
||||
box->y = clip->y1;
|
||||
box->z = 0;
|
||||
box->w = drm_rect_width(clip);
|
||||
box->h = drm_rect_height(clip);
|
||||
box->d = 1;
|
||||
|
||||
return sizeof(*box);
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *bb)
|
||||
{
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer_bo *vfbbo;
|
||||
SVGA3dCmdSurfaceDMASuffix *suffix = cmd;
|
||||
|
||||
stdu = container_of(update->du, typeof(*stdu), base);
|
||||
vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
|
||||
|
||||
suffix->suffixSize = sizeof(*suffix);
|
||||
suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE;
|
||||
|
||||
vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2,
|
||||
bb->y1, bb->y2);
|
||||
|
||||
return sizeof(*suffix) + sizeof(struct vmw_stdu_update);
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update,
|
||||
void *cmd, uint32_t num_hits)
|
||||
{
|
||||
struct vmw_du_update_plane_buffer *bo_update =
|
||||
container_of(update, typeof(*bo_update), base);
|
||||
|
||||
bo_update->fb_left = INT_MAX;
|
||||
bo_update->fb_top = INT_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update,
|
||||
void *cmd, struct drm_rect *clip,
|
||||
uint32_t fb_x, uint32_t fb_y)
|
||||
{
|
||||
struct vmw_du_update_plane_buffer *bo_update =
|
||||
container_of(update, typeof(*bo_update), base);
|
||||
|
||||
bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x);
|
||||
bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd,
|
||||
struct drm_rect *bb)
|
||||
{
|
||||
struct vmw_du_update_plane_buffer *bo_update;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer_bo *vfbbo;
|
||||
struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0);
|
||||
struct vmw_stdu_update_gb_image *cmd_img = cmd;
|
||||
struct vmw_stdu_update *cmd_update;
|
||||
struct ttm_buffer_object *src_bo, *dst_bo;
|
||||
u32 src_offset, dst_offset;
|
||||
s32 src_pitch, dst_pitch;
|
||||
s32 width, height;
|
||||
|
||||
bo_update = container_of(update, typeof(*bo_update), base);
|
||||
stdu = container_of(update->du, typeof(*stdu), base);
|
||||
vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
|
||||
|
||||
width = bb->x2 - bb->x1;
|
||||
height = bb->y2 - bb->y1;
|
||||
|
||||
diff.cpp = stdu->cpp;
|
||||
|
||||
dst_bo = &stdu->display_srf->res.backup->base;
|
||||
dst_pitch = stdu->display_srf->base_size.width * stdu->cpp;
|
||||
dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp;
|
||||
|
||||
src_bo = &vfbbo->buffer->base;
|
||||
src_pitch = update->vfb->base.pitches[0];
|
||||
src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left *
|
||||
stdu->cpp;
|
||||
|
||||
(void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo,
|
||||
src_offset, src_pitch, width * stdu->cpp, height,
|
||||
&diff);
|
||||
|
||||
if (drm_rect_visible(&diff.rect)) {
|
||||
SVGA3dBox *box = &cmd_img->body.box;
|
||||
|
||||
cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
|
||||
cmd_img->header.size = sizeof(cmd_img->body);
|
||||
cmd_img->body.image.sid = stdu->display_srf->res.id;
|
||||
cmd_img->body.image.face = 0;
|
||||
cmd_img->body.image.mipmap = 0;
|
||||
|
||||
box->x = diff.rect.x1;
|
||||
box->y = diff.rect.y1;
|
||||
box->z = 0;
|
||||
box->w = drm_rect_width(&diff.rect);
|
||||
box->h = drm_rect_height(&diff.rect);
|
||||
box->d = 1;
|
||||
|
||||
cmd_update = (struct vmw_stdu_update *)&cmd_img[1];
|
||||
vmw_stdu_populate_update(cmd_update, stdu->base.unit,
|
||||
diff.rect.x1, diff.rect.x2,
|
||||
diff.rect.y1, diff.rect.y2);
|
||||
|
||||
return sizeof(*cmd_img) + sizeof(*cmd_update);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_stdu_plane_update_bo - Update display unit for bo backed fb.
|
||||
* @dev_priv: device private.
|
||||
* @plane: plane state.
|
||||
* @old_state: old plane state.
|
||||
* @vfb: framebuffer which is blitted to display unit.
|
||||
* @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
|
||||
* The returned fence pointer may be NULL in which case the device
|
||||
* has already synchronized.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
|
||||
struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state,
|
||||
struct vmw_framebuffer *vfb,
|
||||
struct vmw_fence_obj **out_fence)
|
||||
{
|
||||
struct vmw_du_update_plane_buffer bo_update;
|
||||
|
||||
memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
|
||||
bo_update.base.plane = plane;
|
||||
bo_update.base.old_state = old_state;
|
||||
bo_update.base.dev_priv = dev_priv;
|
||||
bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
|
||||
bo_update.base.vfb = vfb;
|
||||
bo_update.base.out_fence = out_fence;
|
||||
bo_update.base.mutex = NULL;
|
||||
bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
|
||||
bo_update.base.intr = false;
|
||||
|
||||
/*
|
||||
* VM without 3D support don't have surface DMA command and framebuffer
|
||||
* should be moved out of VRAM.
|
||||
*/
|
||||
if (bo_update.base.cpu_blit) {
|
||||
bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu;
|
||||
bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu;
|
||||
bo_update.base.clip = vmw_stdu_bo_clip_cpu;
|
||||
bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu;
|
||||
} else {
|
||||
bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size;
|
||||
bo_update.base.pre_clip = vmw_stdu_bo_populate_dma;
|
||||
bo_update.base.clip = vmw_stdu_bo_populate_clip;
|
||||
bo_update.base.post_clip = vmw_stdu_bo_populate_update;
|
||||
}
|
||||
|
||||
return vmw_du_helper_plane_update(&bo_update.base);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
struct vmw_framebuffer_surface *vfbs;
|
||||
uint32_t size = 0;
|
||||
|
||||
vfbs = container_of(update->vfb, typeof(*vfbs), base);
|
||||
|
||||
if (vfbs->is_bo_proxy)
|
||||
size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
|
||||
|
||||
size += sizeof(struct vmw_stdu_update);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
struct vmw_framebuffer_surface *vfbs;
|
||||
uint32_t size = 0;
|
||||
|
||||
vfbs = container_of(update->vfb, typeof(*vfbs), base);
|
||||
|
||||
if (vfbs->is_bo_proxy)
|
||||
size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
|
||||
|
||||
size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) *
|
||||
num_hits + sizeof(struct vmw_stdu_update);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd)
|
||||
{
|
||||
struct vmw_framebuffer_surface *vfbs;
|
||||
struct drm_plane_state *state = update->plane->state;
|
||||
struct drm_plane_state *old_state = update->old_state;
|
||||
struct vmw_stdu_update_gb_image *cmd_update = cmd;
|
||||
struct drm_atomic_helper_damage_iter iter;
|
||||
struct drm_rect clip;
|
||||
uint32_t copy_size = 0;
|
||||
|
||||
vfbs = container_of(update->vfb, typeof(*vfbs), base);
|
||||
|
||||
/*
|
||||
* proxy surface is special where a buffer object type fb is wrapped
|
||||
* in a surface and need an update gb image command to sync with device.
|
||||
*/
|
||||
drm_atomic_helper_damage_iter_init(&iter, old_state, state);
|
||||
drm_atomic_for_each_plane_damage(&iter, &clip) {
|
||||
SVGA3dBox *box = &cmd_update->body.box;
|
||||
|
||||
cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
|
||||
cmd_update->header.size = sizeof(cmd_update->body);
|
||||
cmd_update->body.image.sid = vfbs->surface->res.id;
|
||||
cmd_update->body.image.face = 0;
|
||||
cmd_update->body.image.mipmap = 0;
|
||||
|
||||
box->x = clip.x1;
|
||||
box->y = clip.y1;
|
||||
box->z = 0;
|
||||
box->w = drm_rect_width(&clip);
|
||||
box->h = drm_rect_height(&clip);
|
||||
box->d = 1;
|
||||
|
||||
copy_size += sizeof(*cmd_update);
|
||||
cmd_update++;
|
||||
}
|
||||
|
||||
return copy_size;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd,
|
||||
uint32_t num_hits)
|
||||
{
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer_surface *vfbs;
|
||||
struct vmw_stdu_surface_copy *cmd_copy = cmd;
|
||||
|
||||
stdu = container_of(update->du, typeof(*stdu), base);
|
||||
vfbs = container_of(update->vfb, typeof(*vfbs), base);
|
||||
|
||||
cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY;
|
||||
cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) *
|
||||
num_hits;
|
||||
cmd_copy->body.src.sid = vfbs->surface->res.id;
|
||||
cmd_copy->body.dest.sid = stdu->display_srf->res.id;
|
||||
|
||||
return sizeof(*cmd_copy);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd,
|
||||
struct drm_rect *clip, uint32_t fb_x,
|
||||
uint32_t fb_y)
|
||||
{
|
||||
struct SVGA3dCopyBox *box = cmd;
|
||||
|
||||
box->srcx = fb_x;
|
||||
box->srcy = fb_y;
|
||||
box->srcz = 0;
|
||||
box->x = clip->x1;
|
||||
box->y = clip->y1;
|
||||
box->z = 0;
|
||||
box->w = drm_rect_width(clip);
|
||||
box->h = drm_rect_height(clip);
|
||||
box->d = 1;
|
||||
|
||||
return sizeof(*box);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd,
|
||||
struct drm_rect *bb)
|
||||
{
|
||||
vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1,
|
||||
bb->y2);
|
||||
|
||||
return sizeof(struct vmw_stdu_update);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_stdu_plane_update_surface - Update display unit for surface backed fb
|
||||
* @dev_priv: Device private
|
||||
* @plane: Plane state
|
||||
* @old_state: Old plane state
|
||||
* @vfb: Framebuffer which is blitted to display unit
|
||||
* @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
|
||||
* The returned fence pointer may be NULL in which case the device
|
||||
* has already synchronized.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
|
||||
struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state,
|
||||
struct vmw_framebuffer *vfb,
|
||||
struct vmw_fence_obj **out_fence)
|
||||
{
|
||||
struct vmw_du_update_plane srf_update;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct vmw_framebuffer_surface *vfbs;
|
||||
|
||||
stdu = vmw_crtc_to_stdu(plane->state->crtc);
|
||||
vfbs = container_of(vfb, typeof(*vfbs), base);
|
||||
|
||||
memset(&srf_update, 0, sizeof(struct vmw_du_update_plane));
|
||||
srf_update.plane = plane;
|
||||
srf_update.old_state = old_state;
|
||||
srf_update.dev_priv = dev_priv;
|
||||
srf_update.du = vmw_crtc_to_du(plane->state->crtc);
|
||||
srf_update.vfb = vfb;
|
||||
srf_update.out_fence = out_fence;
|
||||
srf_update.mutex = &dev_priv->cmdbuf_mutex;
|
||||
srf_update.cpu_blit = false;
|
||||
srf_update.intr = true;
|
||||
|
||||
if (vfbs->is_bo_proxy)
|
||||
srf_update.post_prepare = vmw_stdu_surface_update_proxy;
|
||||
|
||||
if (vfbs->surface->res.id != stdu->display_srf->res.id) {
|
||||
srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size;
|
||||
srf_update.pre_clip = vmw_stdu_surface_populate_copy;
|
||||
srf_update.clip = vmw_stdu_surface_populate_clip;
|
||||
} else {
|
||||
srf_update.calc_fifo_size =
|
||||
vmw_stdu_surface_fifo_size_same_display;
|
||||
}
|
||||
|
||||
srf_update.post_clip = vmw_stdu_surface_populate_update;
|
||||
|
||||
return vmw_du_helper_plane_update(&srf_update);
|
||||
}
|
||||
|
||||
/**
|
||||
* vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
|
||||
*
|
||||
* @plane: display plane
|
||||
* @old_state: Only used to get crtc info
|
||||
*
|
||||
@ -1277,17 +1603,14 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_crtc *crtc = plane->state->crtc;
|
||||
struct vmw_screen_target_display_unit *stdu;
|
||||
struct drm_pending_vblank_event *event;
|
||||
struct vmw_fence_obj *fence = NULL;
|
||||
struct vmw_private *dev_priv;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We cannot really fail this function, so if we do, then output an
|
||||
* error and maintain consistent atomic state.
|
||||
*/
|
||||
/* If case of device error, maintain consistent atomic state */
|
||||
if (crtc && plane->state->fb) {
|
||||
struct vmw_framebuffer *vfb =
|
||||
vmw_framebuffer_to_vfb(plane->state->fb);
|
||||
struct drm_vmw_rect vclips;
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
@ -1295,23 +1618,17 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
stdu->content_fb_type = vps->content_fb_type;
|
||||
stdu->cpp = vps->cpp;
|
||||
|
||||
vclips.x = crtc->x;
|
||||
vclips.y = crtc->y;
|
||||
vclips.w = crtc->mode.hdisplay;
|
||||
vclips.h = crtc->mode.vdisplay;
|
||||
|
||||
ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to bind surface to STDU.\n");
|
||||
|
||||
if (vfb->bo)
|
||||
ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL,
|
||||
&vclips, 1, 1, true, false,
|
||||
crtc);
|
||||
ret = vmw_stdu_plane_update_bo(dev_priv, plane,
|
||||
old_state, vfb, &fence);
|
||||
else
|
||||
ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL,
|
||||
&vclips, NULL, 0, 0,
|
||||
1, 1, NULL, crtc);
|
||||
ret = vmw_stdu_plane_update_surface(dev_priv, plane,
|
||||
old_state, vfb,
|
||||
&fence);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to update STDU.\n");
|
||||
} else {
|
||||
@ -1319,12 +1636,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
stdu = vmw_crtc_to_stdu(crtc);
|
||||
dev_priv = vmw_priv(crtc->dev);
|
||||
|
||||
/*
|
||||
* When disabling a plane, CRTC and FB should always be NULL
|
||||
* together, otherwise it's an error.
|
||||
* Here primary plane is being disable so blank the screen
|
||||
* target display unit, if not already done.
|
||||
*/
|
||||
/* Blank STDU when fb and crtc are NULL */
|
||||
if (!stdu->defined)
|
||||
return;
|
||||
|
||||
@ -1339,36 +1651,25 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
return;
|
||||
}
|
||||
|
||||
/* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */
|
||||
event = crtc->state->event;
|
||||
/*
|
||||
* In case of failure and other cases, vblank event will be sent in
|
||||
* vmw_du_crtc_atomic_flush.
|
||||
*/
|
||||
if (event && (ret == 0)) {
|
||||
struct vmw_fence_obj *fence = NULL;
|
||||
if (event && fence) {
|
||||
struct drm_file *file_priv = event->base.file_priv;
|
||||
|
||||
vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
|
||||
|
||||
/*
|
||||
* If fence is NULL, then already sync.
|
||||
*/
|
||||
if (fence) {
|
||||
ret = vmw_event_fence_action_queue(
|
||||
file_priv, fence, &event->base,
|
||||
&event->event.vbl.tv_sec,
|
||||
&event->event.vbl.tv_usec,
|
||||
true);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to queue event on fence.\n");
|
||||
else
|
||||
crtc->state->event = NULL;
|
||||
|
||||
vmw_fence_obj_unreference(&fence);
|
||||
}
|
||||
} else {
|
||||
(void) vmw_fifo_flush(dev_priv, false);
|
||||
ret = vmw_event_fence_action_queue(file_priv,
|
||||
fence,
|
||||
&event->base,
|
||||
&event->event.vbl.tv_sec,
|
||||
&event->event.vbl.tv_usec,
|
||||
true);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to queue event on fence.\n");
|
||||
else
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
|
||||
if (fence)
|
||||
vmw_fence_obj_unreference(&fence);
|
||||
}
|
||||
|
||||
|
||||
@ -1456,11 +1757,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
stdu->base.pref_active = (unit == 0);
|
||||
stdu->base.pref_width = dev_priv->initial_width;
|
||||
stdu->base.pref_height = dev_priv->initial_height;
|
||||
|
||||
/*
|
||||
* Remove this after enabling atomic because property values can
|
||||
* only exist in a state object
|
||||
*/
|
||||
stdu->base.is_implicit = false;
|
||||
|
||||
/* Initialize primary plane */
|
||||
@ -1477,6 +1773,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
}
|
||||
|
||||
drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
|
||||
drm_plane_enable_fb_damage_clips(primary);
|
||||
|
||||
/* Initialize cursor plane */
|
||||
vmw_du_plane_reset(cursor);
|
||||
@ -1505,7 +1802,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
|
||||
drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs);
|
||||
connector->status = vmw_du_connector_detect(connector, false);
|
||||
vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
|
||||
|
||||
ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs,
|
||||
DRM_MODE_ENCODER_VIRTUAL, NULL);
|
||||
@ -1543,11 +1839,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
|
||||
dev->mode_config.suggested_x_property, 0);
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.suggested_y_property, 0);
|
||||
if (dev_priv->implicit_placement_property)
|
||||
drm_object_attach_property
|
||||
(&connector->base,
|
||||
dev_priv->implicit_placement_property,
|
||||
stdu->base.is_implicit);
|
||||
return 0;
|
||||
|
||||
err_free_unregister:
|
||||
@ -1616,8 +1907,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
|
||||
|
||||
dev_priv->active_display_unit = vmw_du_screen_target;
|
||||
|
||||
vmw_kms_create_implicit_placement_property(dev_priv, false);
|
||||
|
||||
for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
|
||||
ret = vmw_stdu_init(dev_priv, i);
|
||||
|
||||
|
99
include/drm/drm_damage_helper.h
Normal file
99
include/drm/drm_damage_helper.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (c) 2018 VMware, Inc., Palo Alto, CA., USA
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* 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, sub license, 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 (including the
|
||||
* next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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:
|
||||
* Deepak Rawat <drawat@vmware.com>
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef DRM_DAMAGE_HELPER_H_
|
||||
#define DRM_DAMAGE_HELPER_H_
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
|
||||
/**
|
||||
* drm_atomic_for_each_plane_damage - Iterator macro for plane damage.
|
||||
* @iter: The iterator to advance.
|
||||
* @rect: Return a rectangle in fb coordinate clipped to plane src.
|
||||
*
|
||||
* Note that if the first call to iterator macro return false then no need to do
|
||||
* plane update. Iterator will return full plane src when damage is not passed
|
||||
* by user-space.
|
||||
*/
|
||||
#define drm_atomic_for_each_plane_damage(iter, rect) \
|
||||
while (drm_atomic_helper_damage_iter_next(iter, rect))
|
||||
|
||||
/**
|
||||
* struct drm_atomic_helper_damage_iter - Closure structure for damage iterator.
|
||||
*
|
||||
* This structure tracks state needed to walk the list of plane damage clips.
|
||||
*/
|
||||
struct drm_atomic_helper_damage_iter {
|
||||
/* private: Plane src in whole number. */
|
||||
struct drm_rect plane_src;
|
||||
/* private: Rectangles in plane damage blob. */
|
||||
const struct drm_rect *clips;
|
||||
/* private: Number of rectangles in plane damage blob. */
|
||||
uint32_t num_clips;
|
||||
/* private: Current clip iterator is advancing on. */
|
||||
uint32_t curr_clip;
|
||||
/* private: Whether need full plane update. */
|
||||
bool full_update;
|
||||
};
|
||||
|
||||
void drm_plane_enable_fb_damage_clips(struct drm_plane *plane);
|
||||
void drm_atomic_helper_check_plane_damage(struct drm_atomic_state *state,
|
||||
struct drm_plane_state *plane_state);
|
||||
int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv, unsigned int flags,
|
||||
unsigned int color, struct drm_clip_rect *clips,
|
||||
unsigned int num_clips);
|
||||
void
|
||||
drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
|
||||
const struct drm_plane_state *old_state,
|
||||
const struct drm_plane_state *new_state);
|
||||
bool
|
||||
drm_atomic_helper_damage_iter_next(struct drm_atomic_helper_damage_iter *iter,
|
||||
struct drm_rect *rect);
|
||||
|
||||
/**
|
||||
* drm_helper_get_plane_damage_clips - Returns damage clips in &drm_rect.
|
||||
* @state: Plane state.
|
||||
*
|
||||
* Returns plane damage rectangles in internal &drm_rect. Currently &drm_rect
|
||||
* can be obtained by simply typecasting &drm_mode_rect. This is because both
|
||||
* are signed 32 and during drm_atomic_check_only() it is verified that damage
|
||||
* clips are inside fb.
|
||||
*
|
||||
* Return: Clips in plane fb_damage_clips blob property.
|
||||
*/
|
||||
static inline struct drm_rect *
|
||||
drm_helper_get_plane_damage_clips(const struct drm_plane_state *state)
|
||||
{
|
||||
return (struct drm_rect *)drm_plane_get_damage_clips(state);
|
||||
}
|
||||
|
||||
#endif
|
@ -633,6 +633,15 @@ struct drm_mode_config {
|
||||
* &drm_crtc.
|
||||
*/
|
||||
struct drm_property *prop_crtc_id;
|
||||
/**
|
||||
* @prop_fb_damage_clips: Optional plane property to mark damaged
|
||||
* regions on the plane in framebuffer coordinates of the framebuffer
|
||||
* attached to the plane.
|
||||
*
|
||||
* The layout of blob data is simply an array of &drm_mode_rect. Unlike
|
||||
* plane src coordinates, damage clips are not in 16.16 fixed point.
|
||||
*/
|
||||
struct drm_property *prop_fb_damage_clips;
|
||||
/**
|
||||
* @prop_active: Default atomic CRTC property to control the active
|
||||
* state, which is the simplified implementation for DPMS in atomic
|
||||
|
@ -173,6 +173,16 @@ struct drm_plane_state {
|
||||
*/
|
||||
enum drm_color_range color_range;
|
||||
|
||||
/**
|
||||
* @fb_damage_clips:
|
||||
*
|
||||
* Blob representing damage (area in plane framebuffer that changed
|
||||
* since last plane update) as an array of &drm_mode_rect in framebuffer
|
||||
* coodinates of the attached framebuffer. Note that unlike plane src,
|
||||
* damage clips are not in 16.16 fixed point.
|
||||
*/
|
||||
struct drm_property_blob *fb_damage_clips;
|
||||
|
||||
/** @src: clipped source coordinates of the plane (in 16.16) */
|
||||
/** @dst: clipped destination coordinates of the plane */
|
||||
struct drm_rect src, dst;
|
||||
@ -800,5 +810,37 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev,
|
||||
|
||||
bool drm_any_plane_has_format(struct drm_device *dev,
|
||||
u32 format, u64 modifier);
|
||||
/**
|
||||
* drm_plane_get_damage_clips_count - Returns damage clips count.
|
||||
* @state: Plane state.
|
||||
*
|
||||
* Simple helper to get the number of &drm_mode_rect clips set by user-space
|
||||
* during plane update.
|
||||
*
|
||||
* Return: Number of clips in plane fb_damage_clips blob property.
|
||||
*/
|
||||
static inline unsigned int
|
||||
drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
|
||||
{
|
||||
return (state && state->fb_damage_clips) ?
|
||||
state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_plane_get_damage_clips - Returns damage clips.
|
||||
* @state: Plane state.
|
||||
*
|
||||
* Note that this function returns uapi type &drm_mode_rect. Drivers might
|
||||
* instead be interested in internal &drm_rect which can be obtained by calling
|
||||
* drm_helper_get_plane_damage_clips().
|
||||
*
|
||||
* Return: Damage clips in plane fb_damage_clips blob property.
|
||||
*/
|
||||
static inline struct drm_mode_rect *
|
||||
drm_plane_get_damage_clips(const struct drm_plane_state *state)
|
||||
{
|
||||
return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?
|
||||
state->fb_damage_clips->data : NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -888,6 +888,25 @@ struct drm_mode_revoke_lease {
|
||||
__u32 lessee_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_mode_rect - Two dimensional rectangle.
|
||||
* @x1: Horizontal starting coordinate (inclusive).
|
||||
* @y1: Vertical starting coordinate (inclusive).
|
||||
* @x2: Horizontal ending coordinate (exclusive).
|
||||
* @y2: Vertical ending coordinate (exclusive).
|
||||
*
|
||||
* With drm subsystem using struct drm_rect to manage rectangular area this
|
||||
* export it to user-space.
|
||||
*
|
||||
* Currently used by drm_mode_atomic blob property FB_DAMAGE_CLIPS.
|
||||
*/
|
||||
struct drm_mode_rect {
|
||||
__s32 x1;
|
||||
__s32 y1;
|
||||
__s32 x2;
|
||||
__s32 y2;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user