diff options
Diffstat (limited to 'drivers/gpu/drm/virtio/virtgpu_plane.c')
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_plane.c | 154 |
1 files changed, 103 insertions, 51 deletions
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 024c2aa0c929..d1c3f5fbfee4 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -23,9 +23,12 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "virtgpu_drv.h" -#include <drm/drm_plane_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_plane_helper.h> + +#include "virtgpu_drv.h" static const uint32_t virtio_gpu_formats[] = { DRM_FORMAT_HOST_XRGB8888, @@ -82,7 +85,45 @@ static const struct drm_plane_funcs virtio_gpu_plane_funcs = { static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { - return 0; + bool is_cursor = plane->type == DRM_PLANE_TYPE_CURSOR; + struct drm_crtc_state *crtc_state; + int ret; + + if (!state->fb || WARN_ON(!state->crtc)) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + ret = drm_atomic_helper_check_plane_state(state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + is_cursor, true); + return ret; +} + +static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev, + struct drm_plane_state *state, + struct drm_rect *rect) +{ + struct virtio_gpu_object *bo = + gem_to_virtio_gpu_obj(state->fb->obj[0]); + struct virtio_gpu_object_array *objs; + uint32_t w = rect->x2 - rect->x1; + uint32_t h = rect->y2 - rect->y1; + uint32_t x = rect->x1; + uint32_t y = rect->y1; + uint32_t off = x * state->fb->format->cpp[0] + + y * state->fb->pitches[0]; + + objs = virtio_gpu_array_alloc(1); + if (!objs) + return; + virtio_gpu_array_add_obj(objs, &bo->base.base); + + virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y, + objs, NULL); } static void virtio_gpu_primary_plane_update(struct drm_plane *plane, @@ -91,9 +132,8 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_output *output = NULL; - struct virtio_gpu_framebuffer *vgfb; struct virtio_gpu_object *bo; - uint32_t handle; + struct drm_rect rect; if (plane->state->crtc) output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); @@ -102,40 +142,52 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, if (WARN_ON(!output)) return; - if (plane->state->fb && output->enabled) { - vgfb = to_virtio_gpu_framebuffer(plane->state->fb); - bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); - handle = bo->hw_res_handle; - if (bo->dumb) { - virtio_gpu_cmd_transfer_to_host_2d - (vgdev, bo, 0, - cpu_to_le32(plane->state->src_w >> 16), - cpu_to_le32(plane->state->src_h >> 16), - cpu_to_le32(plane->state->src_x >> 16), - cpu_to_le32(plane->state->src_y >> 16), NULL); - } - } else { - handle = 0; + if (!plane->state->fb || !output->enabled) { + DRM_DEBUG("nofb\n"); + virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + 0, 0); + return; + } + + if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect)) + return; + + virtio_gpu_disable_notify(vgdev); + + bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]); + if (bo->dumb) + virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect); + + if (plane->state->fb != old_state->fb || + plane->state->src_w != old_state->src_w || + plane->state->src_h != old_state->src_h || + plane->state->src_x != old_state->src_x || + plane->state->src_y != old_state->src_y) { + DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", + bo->hw_res_handle, + plane->state->crtc_w, plane->state->crtc_h, + plane->state->crtc_x, plane->state->crtc_y, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->src_x >> 16, + plane->state->src_y >> 16); + virtio_gpu_cmd_set_scanout(vgdev, output->index, + bo->hw_res_handle, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->src_x >> 16, + plane->state->src_y >> 16); } - DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", handle, - plane->state->crtc_w, plane->state->crtc_h, - plane->state->crtc_x, plane->state->crtc_y, - plane->state->src_w >> 16, - plane->state->src_h >> 16, - plane->state->src_x >> 16, - plane->state->src_y >> 16); - virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, - plane->state->src_w >> 16, - plane->state->src_h >> 16, - plane->state->src_x >> 16, - plane->state->src_y >> 16); - if (handle) - virtio_gpu_cmd_resource_flush(vgdev, handle, - plane->state->src_x >> 16, - plane->state->src_y >> 16, - plane->state->src_w >> 16, - plane->state->src_h >> 16); + virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, + rect.x1, + rect.y1, + rect.x2 - rect.x1, + rect.y2 - rect.y1); + + virtio_gpu_enable_notify(vgdev); } static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, @@ -184,7 +236,6 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, struct virtio_gpu_framebuffer *vgfb; struct virtio_gpu_object *bo = NULL; uint32_t handle; - int ret = 0; if (plane->state->crtc) output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); @@ -203,20 +254,21 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, if (bo && bo->dumb && (plane->state->fb != old_state->fb)) { /* new cursor -- update & wait */ + struct virtio_gpu_object_array *objs; + + objs = virtio_gpu_array_alloc(1); + if (!objs) + return; + virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]); + virtio_gpu_array_lock_resv(objs); virtio_gpu_cmd_transfer_to_host_2d - (vgdev, bo, 0, - cpu_to_le32(plane->state->crtc_w), - cpu_to_le32(plane->state->crtc_h), - 0, 0, vgfb->fence); - ret = virtio_gpu_object_reserve(bo, false); - if (!ret) { - reservation_object_add_excl_fence(bo->tbo.resv, - &vgfb->fence->f); - dma_fence_put(&vgfb->fence->f); - vgfb->fence = NULL; - virtio_gpu_object_unreserve(bo); - virtio_gpu_object_wait(bo, false); - } + (vgdev, 0, + plane->state->crtc_w, + plane->state->crtc_h, + 0, 0, objs, vgfb->fence); + dma_fence_wait(&vgfb->fence->f, true); + dma_fence_put(&vgfb->fence->f); + vgfb->fence = NULL; } if (plane->state->fb != old_state->fb) { |