diff options
Diffstat (limited to 'drivers/gpu/drm/vkms')
-rw-r--r-- | drivers/gpu/drm/vkms/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_composer.c (renamed from drivers/gpu/drm/vkms/vkms_crc.c) | 169 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_crtc.c | 100 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_drv.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_drv.h | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_gem.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_output.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_plane.c | 46 |
8 files changed, 254 insertions, 164 deletions
diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index 89f09bec7b23..0b767d7efa24 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o vkms_crc.o +vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o vkms_composer.o obj-$(CONFIG_DRM_VKMS) += vkms.o diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_composer.c index e66ff25c008e..d5585695c64d 100644 --- a/drivers/gpu/drm/vkms/vkms_crc.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -1,34 +1,37 @@ // SPDX-License-Identifier: GPL-2.0+ -#include "vkms_drv.h" #include <linux/crc32.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_vblank.h> + +#include "vkms_drv.h" /** * compute_crc - Compute CRC value on output frame * * @vaddr_out: address to final framebuffer - * @crc_out: framebuffer's metadata + * @composer: framebuffer's metadata * * returns CRC value computed using crc32 on the visible portion of * the final framebuffer at vaddr_out */ -static uint32_t compute_crc(void *vaddr_out, struct vkms_crc_data *crc_out) +static uint32_t compute_crc(void *vaddr_out, struct vkms_composer *composer) { int i, j, src_offset; - int x_src = crc_out->src.x1 >> 16; - int y_src = crc_out->src.y1 >> 16; - int h_src = drm_rect_height(&crc_out->src) >> 16; - int w_src = drm_rect_width(&crc_out->src) >> 16; + int x_src = composer->src.x1 >> 16; + int y_src = composer->src.y1 >> 16; + int h_src = drm_rect_height(&composer->src) >> 16; + int w_src = drm_rect_width(&composer->src) >> 16; u32 crc = 0; for (i = y_src; i < y_src + h_src; ++i) { for (j = x_src; j < x_src + w_src; ++j) { - src_offset = crc_out->offset - + (i * crc_out->pitch) - + (j * crc_out->cpp); + src_offset = composer->offset + + (i * composer->pitch) + + (j * composer->cpp); /* XRGB format ignores Alpha channel */ memset(vaddr_out + src_offset + 24, 0, 8); crc = crc32_le(crc, vaddr_out + src_offset, @@ -43,8 +46,8 @@ static uint32_t compute_crc(void *vaddr_out, struct vkms_crc_data *crc_out) * blend - belnd value at vaddr_src with value at vaddr_dst * @vaddr_dst: destination address * @vaddr_src: source address - * @crc_dst: destination framebuffer's metadata - * @crc_src: source framebuffer's metadata + * @dest_composer: destination framebuffer's metadata + * @src_composer: source framebuffer's metadata * * Blend value at vaddr_src with value at vaddr_dst. * Currently, this function write value at vaddr_src on value @@ -55,31 +58,31 @@ static uint32_t compute_crc(void *vaddr_out, struct vkms_crc_data *crc_out) * instead of overwriting it. */ static void blend(void *vaddr_dst, void *vaddr_src, - struct vkms_crc_data *crc_dst, - struct vkms_crc_data *crc_src) + struct vkms_composer *dest_composer, + struct vkms_composer *src_composer) { int i, j, j_dst, i_dst; int offset_src, offset_dst; - int x_src = crc_src->src.x1 >> 16; - int y_src = crc_src->src.y1 >> 16; + int x_src = src_composer->src.x1 >> 16; + int y_src = src_composer->src.y1 >> 16; - int x_dst = crc_src->dst.x1; - int y_dst = crc_src->dst.y1; - int h_dst = drm_rect_height(&crc_src->dst); - int w_dst = drm_rect_width(&crc_src->dst); + int x_dst = src_composer->dst.x1; + int y_dst = src_composer->dst.y1; + int h_dst = drm_rect_height(&src_composer->dst); + int w_dst = drm_rect_width(&src_composer->dst); int y_limit = y_src + h_dst; int x_limit = x_src + w_dst; for (i = y_src, i_dst = y_dst; i < y_limit; ++i) { for (j = x_src, j_dst = x_dst; j < x_limit; ++j) { - offset_dst = crc_dst->offset - + (i_dst * crc_dst->pitch) - + (j_dst++ * crc_dst->cpp); - offset_src = crc_src->offset - + (i * crc_src->pitch) - + (j * crc_src->cpp); + offset_dst = dest_composer->offset + + (i_dst * dest_composer->pitch) + + (j_dst++ * dest_composer->cpp); + offset_src = src_composer->offset + + (i * src_composer->pitch) + + (j * src_composer->cpp); memcpy(vaddr_dst + offset_dst, vaddr_src + offset_src, sizeof(u32)); @@ -88,31 +91,27 @@ static void blend(void *vaddr_dst, void *vaddr_src, } } -static void compose_cursor(struct vkms_crc_data *cursor_crc, - struct vkms_crc_data *primary_crc, void *vaddr_out) +static void compose_cursor(struct vkms_composer *cursor_composer, + struct vkms_composer *primary_composer, + void *vaddr_out) { struct drm_gem_object *cursor_obj; struct vkms_gem_object *cursor_vkms_obj; - cursor_obj = drm_gem_fb_get_obj(&cursor_crc->fb, 0); + cursor_obj = drm_gem_fb_get_obj(&cursor_composer->fb, 0); cursor_vkms_obj = drm_gem_to_vkms_gem(cursor_obj); - mutex_lock(&cursor_vkms_obj->pages_lock); - if (!cursor_vkms_obj->vaddr) { - DRM_WARN("cursor plane vaddr is NULL"); - goto out; - } - - blend(vaddr_out, cursor_vkms_obj->vaddr, primary_crc, cursor_crc); + if (WARN_ON(!cursor_vkms_obj->vaddr)) + return; -out: - mutex_unlock(&cursor_vkms_obj->pages_lock); + blend(vaddr_out, cursor_vkms_obj->vaddr, + primary_composer, cursor_composer); } -static uint32_t _vkms_get_crc(struct vkms_crc_data *primary_crc, - struct vkms_crc_data *cursor_crc) +static uint32_t _vkms_get_crc(struct vkms_composer *primary_composer, + struct vkms_composer *cursor_composer) { - struct drm_framebuffer *fb = &primary_crc->fb; + struct drm_framebuffer *fb = &primary_composer->fb; struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0); struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj); void *vaddr_out = kzalloc(vkms_obj->gem.size, GFP_KERNEL); @@ -123,20 +122,17 @@ static uint32_t _vkms_get_crc(struct vkms_crc_data *primary_crc, return 0; } - mutex_lock(&vkms_obj->pages_lock); if (WARN_ON(!vkms_obj->vaddr)) { - mutex_unlock(&vkms_obj->pages_lock); kfree(vaddr_out); return crc; } memcpy(vaddr_out, vkms_obj->vaddr, vkms_obj->gem.size); - mutex_unlock(&vkms_obj->pages_lock); - if (cursor_crc) - compose_cursor(cursor_crc, primary_crc, vaddr_out); + if (cursor_composer) + compose_cursor(cursor_composer, primary_composer, vaddr_out); - crc = compute_crc(vaddr_out, primary_crc); + crc = compute_crc(vaddr_out, primary_composer); kfree(vaddr_out); @@ -144,72 +140,57 @@ static uint32_t _vkms_get_crc(struct vkms_crc_data *primary_crc, } /** - * vkms_crc_work_handle - ordered work_struct to compute CRC + * vkms_composer_worker - ordered work_struct to compute CRC * * @work: work_struct * - * Work handler for computing CRCs. work_struct scheduled in + * Work handler for composing and computing CRCs. work_struct scheduled in * an ordered workqueue that's periodically scheduled to run by * _vblank_handle() and flushed at vkms_atomic_crtc_destroy_state(). */ -void vkms_crc_work_handle(struct work_struct *work) +void vkms_composer_worker(struct work_struct *work) { struct vkms_crtc_state *crtc_state = container_of(work, struct vkms_crtc_state, - crc_work); + composer_work); struct drm_crtc *crtc = crtc_state->base.crtc; struct vkms_output *out = drm_crtc_to_vkms_output(crtc); - struct vkms_device *vdev = container_of(out, struct vkms_device, - output); - struct vkms_crc_data *primary_crc = NULL; - struct vkms_crc_data *cursor_crc = NULL; - struct drm_plane *plane; + struct vkms_composer *primary_composer = NULL; + struct vkms_composer *cursor_composer = NULL; u32 crc32 = 0; u64 frame_start, frame_end; - unsigned long flags; + bool crc_pending; - spin_lock_irqsave(&out->state_lock, flags); + spin_lock_irq(&out->composer_lock); frame_start = crtc_state->frame_start; frame_end = crtc_state->frame_end; - spin_unlock_irqrestore(&out->state_lock, flags); - - /* _vblank_handle() hasn't updated frame_start yet */ - if (!frame_start || frame_start == frame_end) - goto out; - - drm_for_each_plane(plane, &vdev->drm) { - struct vkms_plane_state *vplane_state; - struct vkms_crc_data *crc_data; - - vplane_state = to_vkms_plane_state(plane->state); - crc_data = vplane_state->crc_data; + crc_pending = crtc_state->crc_pending; + crtc_state->frame_start = 0; + crtc_state->frame_end = 0; + crtc_state->crc_pending = false; + spin_unlock_irq(&out->composer_lock); - if (drm_framebuffer_read_refcount(&crc_data->fb) == 0) - continue; + /* + * We raced with the vblank hrtimer and previous work already computed + * the crc, nothing to do. + */ + if (!crc_pending) + return; - if (plane->type == DRM_PLANE_TYPE_PRIMARY) - primary_crc = crc_data; - else - cursor_crc = crc_data; - } + if (crtc_state->num_active_planes >= 1) + primary_composer = crtc_state->active_planes[0]->composer; - if (primary_crc) - crc32 = _vkms_get_crc(primary_crc, cursor_crc); + if (crtc_state->num_active_planes == 2) + cursor_composer = crtc_state->active_planes[1]->composer; - frame_end = drm_crtc_accurate_vblank_count(crtc); + if (primary_composer) + crc32 = _vkms_get_crc(primary_composer, cursor_composer); - /* queue_work can fail to schedule crc_work; add crc for - * missing frames + /* + * The worker can fall behind the vblank hrtimer, make sure we catch up. */ while (frame_start <= frame_end) drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32); - -out: - /* to avoid using the same value for frame number again */ - spin_lock_irqsave(&out->state_lock, flags); - crtc_state->frame_end = frame_end; - crtc_state->frame_start = 0; - spin_unlock_irqrestore(&out->state_lock, flags); } static const char * const pipe_crc_sources[] = {"auto"}; @@ -256,17 +237,13 @@ int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) { struct vkms_output *out = drm_crtc_to_vkms_output(crtc); bool enabled = false; - unsigned long flags; int ret = 0; ret = vkms_crc_parse_source(src_name, &enabled); - /* make sure nothing is scheduled on crtc workq */ - flush_workqueue(out->crc_workq); - - spin_lock_irqsave(&out->lock, flags); - out->crc_enabled = enabled; - spin_unlock_irqrestore(&out->lock, flags); + spin_lock_irq(&out->lock); + out->composer_enabled = enabled; + spin_unlock_irq(&out->lock); return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 4d11292bc6f3..927dafaebc76 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -1,15 +1,18 @@ // SPDX-License-Identifier: GPL-2.0+ -#include "vkms_drv.h" +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#include "vkms_drv.h" static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) { struct vkms_output *output = container_of(timer, struct vkms_output, vblank_hrtimer); struct drm_crtc *crtc = &output->crtc; - struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state); + struct vkms_crtc_state *state; u64 ret_overrun; bool ret; @@ -23,20 +26,26 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) if (!ret) DRM_ERROR("vkms failure on handling vblank"); - if (state && output->crc_enabled) { + state = output->composer_state; + if (state && output->composer_enabled) { u64 frame = drm_crtc_accurate_vblank_count(crtc); - /* update frame_start only if a queued vkms_crc_work_handle() + /* update frame_start only if a queued vkms_composer_worker() * has read the data */ - spin_lock(&output->state_lock); - if (!state->frame_start) + spin_lock(&output->composer_lock); + if (!state->crc_pending) state->frame_start = frame; - spin_unlock(&output->state_lock); + else + DRM_DEBUG_DRIVER("crc worker falling behind, frame_start: %llu, frame_end: %llu\n", + state->frame_start, frame); + state->frame_end = frame; + state->crc_pending = true; + spin_unlock(&output->composer_lock); - ret = queue_work(output->crc_workq, &state->crc_work); + ret = queue_work(output->composer_workq, &state->composer_work); if (!ret) - DRM_WARN("failed to queue vkms_crc_work_handle"); + DRM_DEBUG_DRIVER("Composer worker already queued\n"); } spin_unlock(&output->lock); @@ -107,7 +116,7 @@ vkms_atomic_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &vkms_state->base); - INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle); + INIT_WORK(&vkms_state->composer_work, vkms_composer_worker); return &vkms_state->base; } @@ -119,10 +128,9 @@ static void vkms_atomic_crtc_destroy_state(struct drm_crtc *crtc, __drm_atomic_helper_crtc_destroy_state(state); - if (vkms_state) { - flush_work(&vkms_state->crc_work); - kfree(vkms_state); - } + WARN_ON(work_pending(&vkms_state->composer_work)); + kfree(vkms_state->active_planes); + kfree(vkms_state); } static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) @@ -135,7 +143,7 @@ static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) __drm_atomic_helper_crtc_reset(crtc, &vkms_state->base); if (vkms_state) - INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle); + INIT_WORK(&vkms_state->composer_work, vkms_composer_worker); } static const struct drm_crtc_funcs vkms_crtc_funcs = { @@ -152,6 +160,52 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { .verify_crc_source = vkms_verify_crc_source, }; +static int vkms_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct vkms_crtc_state *vkms_state = to_vkms_crtc_state(state); + struct drm_plane *plane; + struct drm_plane_state *plane_state; + int i = 0, ret; + + if (vkms_state->active_planes) + return 0; + + ret = drm_atomic_add_affected_planes(state->state, crtc); + if (ret < 0) + return ret; + + drm_for_each_plane_mask(plane, crtc->dev, state->plane_mask) { + plane_state = drm_atomic_get_existing_plane_state(state->state, + plane); + WARN_ON(!plane_state); + + if (!plane_state->visible) + continue; + + i++; + } + + vkms_state->active_planes = kcalloc(i, sizeof(plane), GFP_KERNEL); + if (!vkms_state->active_planes) + return -ENOMEM; + vkms_state->num_active_planes = i; + + i = 0; + drm_for_each_plane_mask(plane, crtc->dev, state->plane_mask) { + plane_state = drm_atomic_get_existing_plane_state(state->state, + plane); + + if (!plane_state->visible) + continue; + + vkms_state->active_planes[i++] = + to_vkms_plane_state(plane_state); + } + + return 0; +} + static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -170,7 +224,7 @@ static void vkms_crtc_atomic_begin(struct drm_crtc *crtc, struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc); /* This lock is held across the atomic commit to block vblank timer - * from scheduling vkms_crc_work_handle until the crc_data is updated + * from scheduling vkms_composer_worker until the composer is updated */ spin_lock_irq(&vkms_output->lock); } @@ -179,25 +233,27 @@ static void vkms_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc); - unsigned long flags; if (crtc->state->event) { - spin_lock_irqsave(&crtc->dev->event_lock, flags); + spin_lock(&crtc->dev->event_lock); if (drm_crtc_vblank_get(crtc) != 0) drm_crtc_send_vblank_event(crtc, crtc->state->event); else drm_crtc_arm_vblank_event(crtc, crtc->state->event); - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + spin_unlock(&crtc->dev->event_lock); crtc->state->event = NULL; } + vkms_output->composer_state = to_vkms_crtc_state(crtc->state); + spin_unlock_irq(&vkms_output->lock); } static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { + .atomic_check = vkms_crtc_atomic_check, .atomic_begin = vkms_crtc_atomic_begin, .atomic_flush = vkms_crtc_atomic_flush, .atomic_enable = vkms_crtc_atomic_enable, @@ -220,10 +276,10 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); spin_lock_init(&vkms_out->lock); - spin_lock_init(&vkms_out->state_lock); + spin_lock_init(&vkms_out->composer_lock); - vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0); - if (!vkms_out->crc_workq) + vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0); + if (!vkms_out->composer_workq) return -ENOMEM; return ret; diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 738dd6206d85..44ab9f8ef8be 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -10,11 +10,19 @@ */ #include <linux/module.h> -#include <drm/drm_gem.h> +#include <linux/platform_device.h> + +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_gem.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_ioctl.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + #include "vkms_drv.h" #define DRIVER_NAME "vkms" @@ -55,7 +63,36 @@ static void vkms_release(struct drm_device *dev) drm_atomic_helper_shutdown(&vkms->drm); drm_mode_config_cleanup(&vkms->drm); drm_dev_fini(&vkms->drm); - destroy_workqueue(vkms->output.crc_workq); + destroy_workqueue(vkms->output.composer_workq); +} + +static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state) +{ + struct drm_device *dev = old_state->dev; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + int i; + + drm_atomic_helper_commit_modeset_disables(dev, old_state); + + drm_atomic_helper_commit_planes(dev, old_state, 0); + + drm_atomic_helper_commit_modeset_enables(dev, old_state); + + drm_atomic_helper_fake_vblank(old_state); + + drm_atomic_helper_commit_hw_done(old_state); + + drm_atomic_helper_wait_for_vblanks(dev, old_state); + + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { + struct vkms_crtc_state *vkms_state = + to_vkms_crtc_state(old_crtc_state); + + flush_work(&vkms_state->composer_work); + } + + drm_atomic_helper_cleanup_planes(dev, old_state); } static struct drm_driver vkms_driver = { @@ -80,6 +117,10 @@ static const struct drm_mode_config_funcs vkms_mode_funcs = { .atomic_commit = drm_atomic_helper_commit, }; +static const struct drm_mode_config_helper_funcs vkms_mode_config_helpers = { + .atomic_commit_tail = vkms_atomic_commit_tail, +}; + static int vkms_modeset_init(struct vkms_device *vkmsdev) { struct drm_device *dev = &vkmsdev->drm; @@ -91,8 +132,9 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev) dev->mode_config.max_width = XRES_MAX; dev->mode_config.max_height = YRES_MAX; dev->mode_config.preferred_depth = 24; + dev->mode_config.helper_private = &vkms_mode_config_helpers; - return vkms_output_init(vkmsdev); + return vkms_output_init(vkmsdev, 0); } static int __init vkms_init(void) diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index b92c30c66a6f..5a95100fa18b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -3,11 +3,11 @@ #ifndef _VKMS_DRV_H_ #define _VKMS_DRV_H_ -#include <drm/drmP.h> +#include <linux/hrtimer.h> + #include <drm/drm.h> #include <drm/drm_gem.h> #include <drm/drm_encoder.h> -#include <linux/hrtimer.h> #define XRES_MIN 20 #define YRES_MIN 20 @@ -20,7 +20,7 @@ extern bool enable_cursor; -struct vkms_crc_data { +struct vkms_composer { struct drm_framebuffer fb; struct drm_rect src, dst; unsigned int offset; @@ -31,23 +31,30 @@ struct vkms_crc_data { /** * vkms_plane_state - Driver specific plane state * @base: base plane state - * @crc_data: data required for CRC computation + * @composer: data required for composing computation */ struct vkms_plane_state { struct drm_plane_state base; - struct vkms_crc_data *crc_data; + struct vkms_composer *composer; }; /** * vkms_crtc_state - Driver specific CRTC state * @base: base CRTC state - * @crc_work: work struct to compute and add CRC entries + * @composer_work: work struct to compose and add CRC entries * @n_frame_start: start frame number for computed CRC * @n_frame_end: end frame number for computed CRC */ struct vkms_crtc_state { struct drm_crtc_state base; - struct work_struct crc_work; + struct work_struct composer_work; + + int num_active_planes; + /* stack of active planes for crc computation, should be in z order */ + struct vkms_plane_state **active_planes; + + /* below three are protected by vkms_output.composer_lock */ + bool crc_pending; u64 frame_start; u64 frame_end; }; @@ -59,13 +66,16 @@ struct vkms_output { struct hrtimer vblank_hrtimer; ktime_t period_ns; struct drm_pending_vblank_event *event; - bool crc_enabled; - /* ordered wq for crc_work */ - struct workqueue_struct *crc_workq; - /* protects concurrent access to crc_data */ + /* ordered wq for composer_work */ + struct workqueue_struct *composer_workq; + /* protects concurrent access to composer */ spinlock_t lock; - /* protects concurrent access to crtc_state */ - spinlock_t state_lock; + + /* protected by @lock */ + bool composer_enabled; + struct vkms_crtc_state *composer_state; + + spinlock_t composer_lock; }; struct vkms_device { @@ -105,10 +115,10 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, int *max_error, ktime_t *vblank_time, bool in_vblank_irq); -int vkms_output_init(struct vkms_device *vkmsdev); +int vkms_output_init(struct vkms_device *vkmsdev, int index); struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type); + enum drm_plane_type type, int index); /* Gem stuff */ struct drm_gem_object *vkms_gem_create(struct drm_device *dev, @@ -133,6 +143,8 @@ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name); int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name, size_t *values_cnt); -void vkms_crc_work_handle(struct work_struct *work); + +/* Composer Support */ +void vkms_composer_worker(struct work_struct *work); #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c index 69048e73377d..6489bfe0a149 100644 --- a/drivers/gpu/drm/vkms/vkms_gem.c +++ b/drivers/gpu/drm/vkms/vkms_gem.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include <linux/shmem_fs.h> +#include <linux/vmalloc.h> #include "vkms_drv.h" diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 56fb5c2a2315..fb1941a6522c 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -35,7 +35,7 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { .get_modes = vkms_conn_get_modes, }; -int vkms_output_init(struct vkms_device *vkmsdev) +int vkms_output_init(struct vkms_device *vkmsdev, int index) { struct vkms_output *output = &vkmsdev->output; struct drm_device *dev = &vkmsdev->drm; @@ -45,12 +45,12 @@ int vkms_output_init(struct vkms_device *vkmsdev) struct drm_plane *primary, *cursor = NULL; int ret; - primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY); + primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); if (IS_ERR(primary)) return PTR_ERR(primary); if (enable_cursor) { - cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR); + cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); if (IS_ERR(cursor)) { ret = PTR_ERR(cursor); goto err_cursor; diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 0fceb6258422..5fc8f85aaf3d 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0+ -#include "vkms_drv.h" -#include <drm/drm_plane_helper.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_plane_helper.h> + +#include "vkms_drv.h" static const u32 vkms_formats[] = { DRM_FORMAT_XRGB8888, @@ -18,20 +20,20 @@ static struct drm_plane_state * vkms_plane_duplicate_state(struct drm_plane *plane) { struct vkms_plane_state *vkms_state; - struct vkms_crc_data *crc_data; + struct vkms_composer *composer; vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL); if (!vkms_state) return NULL; - crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL); - if (!crc_data) { - DRM_DEBUG_KMS("Couldn't allocate crc_data\n"); + composer = kzalloc(sizeof(*composer), GFP_KERNEL); + if (!composer) { + DRM_DEBUG_KMS("Couldn't allocate composer\n"); kfree(vkms_state); return NULL; } - vkms_state->crc_data = crc_data; + vkms_state->composer = composer; __drm_atomic_helper_plane_duplicate_state(plane, &vkms_state->base); @@ -49,12 +51,12 @@ static void vkms_plane_destroy_state(struct drm_plane *plane, /* dropping the reference we acquired in * vkms_primary_plane_update() */ - if (drm_framebuffer_read_refcount(&vkms_state->crc_data->fb)) - drm_framebuffer_put(&vkms_state->crc_data->fb); + if (drm_framebuffer_read_refcount(&vkms_state->composer->fb)) + drm_framebuffer_put(&vkms_state->composer->fb); } - kfree(vkms_state->crc_data); - vkms_state->crc_data = NULL; + kfree(vkms_state->composer); + vkms_state->composer = NULL; __drm_atomic_helper_plane_destroy_state(old_state); kfree(vkms_state); @@ -91,21 +93,21 @@ static void vkms_plane_atomic_update(struct drm_plane *plane, { struct vkms_plane_state *vkms_plane_state; struct drm_framebuffer *fb = plane->state->fb; - struct vkms_crc_data *crc_data; + struct vkms_composer *composer; if (!plane->state->crtc || !fb) return; vkms_plane_state = to_vkms_plane_state(plane->state); - crc_data = vkms_plane_state->crc_data; - memcpy(&crc_data->src, &plane->state->src, sizeof(struct drm_rect)); - memcpy(&crc_data->dst, &plane->state->dst, sizeof(struct drm_rect)); - memcpy(&crc_data->fb, fb, sizeof(struct drm_framebuffer)); - drm_framebuffer_get(&crc_data->fb); - crc_data->offset = fb->offsets[0]; - crc_data->pitch = fb->pitches[0]; - crc_data->cpp = fb->format->cpp[0]; + composer = vkms_plane_state->composer; + memcpy(&composer->src, &plane->state->src, sizeof(struct drm_rect)); + memcpy(&composer->dst, &plane->state->dst, sizeof(struct drm_rect)); + memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer)); + drm_framebuffer_get(&composer->fb); + composer->offset = fb->offsets[0]; + composer->pitch = fb->pitches[0]; + composer->cpp = fb->format->cpp[0]; } static int vkms_plane_atomic_check(struct drm_plane *plane, @@ -176,7 +178,7 @@ static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { }; struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type) + enum drm_plane_type type, int index) { struct drm_device *dev = &vkmsdev->drm; const struct drm_plane_helper_funcs *funcs; @@ -198,7 +200,7 @@ struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev, funcs = &vkms_primary_helper_funcs; } - ret = drm_universal_plane_init(dev, plane, 0, + ret = drm_universal_plane_init(dev, plane, 1 << index, &vkms_plane_funcs, formats, nformats, NULL, type, NULL); |