linux/drivers/gpu/drm/vkms/vkms_plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2
   3#include <linux/dma-buf-map.h>
   4
   5#include <drm/drm_atomic.h>
   6#include <drm/drm_atomic_helper.h>
   7#include <drm/drm_fourcc.h>
   8#include <drm/drm_gem_atomic_helper.h>
   9#include <drm/drm_gem_framebuffer_helper.h>
  10#include <drm/drm_plane_helper.h>
  11
  12#include "vkms_drv.h"
  13
  14static const u32 vkms_formats[] = {
  15        DRM_FORMAT_XRGB8888,
  16};
  17
  18static const u32 vkms_plane_formats[] = {
  19        DRM_FORMAT_ARGB8888,
  20        DRM_FORMAT_XRGB8888
  21};
  22
  23static struct drm_plane_state *
  24vkms_plane_duplicate_state(struct drm_plane *plane)
  25{
  26        struct vkms_plane_state *vkms_state;
  27        struct vkms_composer *composer;
  28
  29        vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
  30        if (!vkms_state)
  31                return NULL;
  32
  33        composer = kzalloc(sizeof(*composer), GFP_KERNEL);
  34        if (!composer) {
  35                DRM_DEBUG_KMS("Couldn't allocate composer\n");
  36                kfree(vkms_state);
  37                return NULL;
  38        }
  39
  40        vkms_state->composer = composer;
  41
  42        __drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base);
  43
  44        return &vkms_state->base.base;
  45}
  46
  47static void vkms_plane_destroy_state(struct drm_plane *plane,
  48                                     struct drm_plane_state *old_state)
  49{
  50        struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
  51        struct drm_crtc *crtc = vkms_state->base.base.crtc;
  52
  53        if (crtc) {
  54                /* dropping the reference we acquired in
  55                 * vkms_primary_plane_update()
  56                 */
  57                if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
  58                        drm_framebuffer_put(&vkms_state->composer->fb);
  59        }
  60
  61        kfree(vkms_state->composer);
  62        vkms_state->composer = NULL;
  63
  64        __drm_gem_destroy_shadow_plane_state(&vkms_state->base);
  65        kfree(vkms_state);
  66}
  67
  68static void vkms_plane_reset(struct drm_plane *plane)
  69{
  70        struct vkms_plane_state *vkms_state;
  71
  72        if (plane->state) {
  73                vkms_plane_destroy_state(plane, plane->state);
  74                plane->state = NULL; /* must be set to NULL here */
  75        }
  76
  77        vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
  78        if (!vkms_state) {
  79                DRM_ERROR("Cannot allocate vkms_plane_state\n");
  80                return;
  81        }
  82
  83        __drm_gem_reset_shadow_plane(plane, &vkms_state->base);
  84}
  85
  86static const struct drm_plane_funcs vkms_plane_funcs = {
  87        .update_plane           = drm_atomic_helper_update_plane,
  88        .disable_plane          = drm_atomic_helper_disable_plane,
  89        .reset                  = vkms_plane_reset,
  90        .atomic_duplicate_state = vkms_plane_duplicate_state,
  91        .atomic_destroy_state   = vkms_plane_destroy_state,
  92};
  93
  94static void vkms_plane_atomic_update(struct drm_plane *plane,
  95                                     struct drm_atomic_state *state)
  96{
  97        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
  98                                                                           plane);
  99        struct vkms_plane_state *vkms_plane_state;
 100        struct drm_shadow_plane_state *shadow_plane_state;
 101        struct drm_framebuffer *fb = new_state->fb;
 102        struct vkms_composer *composer;
 103
 104        if (!new_state->crtc || !fb)
 105                return;
 106
 107        vkms_plane_state = to_vkms_plane_state(new_state);
 108        shadow_plane_state = &vkms_plane_state->base;
 109
 110        composer = vkms_plane_state->composer;
 111        memcpy(&composer->src, &new_state->src, sizeof(struct drm_rect));
 112        memcpy(&composer->dst, &new_state->dst, sizeof(struct drm_rect));
 113        memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
 114        memcpy(&composer->map, &shadow_plane_state->data, sizeof(composer->map));
 115        drm_framebuffer_get(&composer->fb);
 116        composer->offset = fb->offsets[0];
 117        composer->pitch = fb->pitches[0];
 118        composer->cpp = fb->format->cpp[0];
 119}
 120
 121static int vkms_plane_atomic_check(struct drm_plane *plane,
 122                                   struct drm_atomic_state *state)
 123{
 124        struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
 125                                                                                 plane);
 126        struct drm_crtc_state *crtc_state;
 127        bool can_position = false;
 128        int ret;
 129
 130        if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
 131                return 0;
 132
 133        crtc_state = drm_atomic_get_crtc_state(state,
 134                                               new_plane_state->crtc);
 135        if (IS_ERR(crtc_state))
 136                return PTR_ERR(crtc_state);
 137
 138        if (plane->type != DRM_PLANE_TYPE_PRIMARY)
 139                can_position = true;
 140
 141        ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
 142                                                  DRM_PLANE_HELPER_NO_SCALING,
 143                                                  DRM_PLANE_HELPER_NO_SCALING,
 144                                                  can_position, true);
 145        if (ret != 0)
 146                return ret;
 147
 148        /* for now primary plane must be visible and full screen */
 149        if (!new_plane_state->visible && !can_position)
 150                return -EINVAL;
 151
 152        return 0;
 153}
 154
 155static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
 156        .atomic_update          = vkms_plane_atomic_update,
 157        .atomic_check           = vkms_plane_atomic_check,
 158        DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
 159};
 160
 161struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
 162                                   enum drm_plane_type type, int index)
 163{
 164        struct drm_device *dev = &vkmsdev->drm;
 165        const struct drm_plane_helper_funcs *funcs;
 166        struct vkms_plane *plane;
 167        const u32 *formats;
 168        int nformats;
 169
 170        switch (type) {
 171        case DRM_PLANE_TYPE_PRIMARY:
 172                formats = vkms_formats;
 173                nformats = ARRAY_SIZE(vkms_formats);
 174                funcs = &vkms_primary_helper_funcs;
 175                break;
 176        case DRM_PLANE_TYPE_CURSOR:
 177        case DRM_PLANE_TYPE_OVERLAY:
 178                formats = vkms_plane_formats;
 179                nformats = ARRAY_SIZE(vkms_plane_formats);
 180                funcs = &vkms_primary_helper_funcs;
 181                break;
 182        default:
 183                formats = vkms_formats;
 184                nformats = ARRAY_SIZE(vkms_formats);
 185                funcs = &vkms_primary_helper_funcs;
 186                break;
 187        }
 188
 189        plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index,
 190                                           &vkms_plane_funcs,
 191                                           formats, nformats,
 192                                           NULL, type, NULL);
 193        if (IS_ERR(plane))
 194                return plane;
 195
 196        drm_plane_helper_add(&plane->base, funcs);
 197
 198        return plane;
 199}
 200