Commit 1f9a5dce authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave Airlie <airlied@redhat.com>
From: Thomas Hellstrom <thellstrom@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181205103554.3675-1-thellstrom@vmware.com
parents fb878d10 9a01135b
......@@ -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 {
......
// 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)
......
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)
// 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,9 +2085,12 @@ 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);
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;
}
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 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
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_primary_plane_atomic_update - formally switches STDU to new plane
* 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,23 +1651,14 @@ 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,
ret = vmw_event_fence_action_queue(file_priv,
fence,
&event->base,
&event->event.vbl.tv_sec,
&event->event.vbl.tv_usec,
true);
......@@ -1363,12 +1666,10 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
DRM_ERROR("Failed to queue event on fence.\n");
else
crtc->state->event = NULL;
}
if (fence)
vmw_fence_obj_unreference(&fence);
}
} else {
(void) vmw_fifo_flush(dev_priv, false);
}
}
......@@ -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);
......
/* 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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment