linux/drivers/gpu/drm/qxl/qxl_draw.c
<<
>>
Prefs
   1/*
   2 * Copyright 2011 Red Hat, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * on the rights to use, copy, modify, merge, publish, distribute, sub
   8 * license, and/or sell copies of the Software, and to permit persons to whom
   9 * the Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21 */
  22
  23#include "qxl_drv.h"
  24#include "qxl_object.h"
  25
  26/* returns a pointer to the already allocated qxl_rect array inside
  27 * the qxl_clip_rects. This is *not* the same as the memory allocated
  28 * on the device, it is offset to qxl_clip_rects.chunk.data */
  29static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
  30                                              struct qxl_drawable *drawable,
  31                                              unsigned num_clips,
  32                                              struct qxl_bo **clips_bo,
  33                                              struct qxl_release *release)
  34{
  35        struct qxl_clip_rects *dev_clips;
  36        int ret;
  37        int size = sizeof(*dev_clips) + sizeof(struct qxl_rect) * num_clips;
  38        ret = qxl_alloc_bo_reserved(qdev, size, clips_bo);
  39        if (ret)
  40                return NULL;
  41
  42        ret = qxl_bo_kmap(*clips_bo, (void **)&dev_clips);
  43        if (ret) {
  44                qxl_bo_unref(clips_bo);
  45                return NULL;
  46        }
  47        dev_clips->num_rects = num_clips;
  48        dev_clips->chunk.next_chunk = 0;
  49        dev_clips->chunk.prev_chunk = 0;
  50        dev_clips->chunk.data_size = sizeof(struct qxl_rect) * num_clips;
  51        return (struct qxl_rect *)dev_clips->chunk.data;
  52}
  53
  54static int
  55make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
  56              const struct qxl_rect *rect,
  57              struct qxl_release **release)
  58{
  59        struct qxl_drawable *drawable;
  60        int i, ret;
  61
  62        ret = qxl_alloc_release_reserved(qdev, sizeof(*drawable),
  63                                         QXL_RELEASE_DRAWABLE, release,
  64                                         NULL);
  65        if (ret)
  66                return ret;
  67
  68        drawable = (struct qxl_drawable *)qxl_release_map(qdev, *release);
  69        drawable->type = type;
  70
  71        drawable->surface_id = surface;         /* Only primary for now */
  72        drawable->effect = QXL_EFFECT_OPAQUE;
  73        drawable->self_bitmap = 0;
  74        drawable->self_bitmap_area.top = 0;
  75        drawable->self_bitmap_area.left = 0;
  76        drawable->self_bitmap_area.bottom = 0;
  77        drawable->self_bitmap_area.right = 0;
  78        /* FIXME: add clipping */
  79        drawable->clip.type = SPICE_CLIP_TYPE_NONE;
  80
  81        /*
  82         * surfaces_dest[i] should apparently be filled out with the
  83         * surfaces that we depend on, and surface_rects should be
  84         * filled with the rectangles of those surfaces that we
  85         * are going to use.
  86         */
  87        for (i = 0; i < 3; ++i)
  88                drawable->surfaces_dest[i] = -1;
  89
  90        if (rect)
  91                drawable->bbox = *rect;
  92
  93        drawable->mm_time = qdev->rom->mm_clock;
  94        qxl_release_unmap(qdev, *release, &drawable->release_info);
  95        return 0;
  96}
  97
  98static int qxl_palette_create_1bit(struct qxl_bo **palette_bo,
  99                                   const struct qxl_fb_image *qxl_fb_image)
 100{
 101        struct qxl_device *qdev = qxl_fb_image->qdev;
 102        const struct fb_image *fb_image = &qxl_fb_image->fb_image;
 103        uint32_t visual = qxl_fb_image->visual;
 104        const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette;
 105        struct qxl_palette *pal;
 106        int ret;
 107        uint32_t fgcolor, bgcolor;
 108        static uint64_t unique; /* we make no attempt to actually set this
 109                                 * correctly globaly, since that would require
 110                                 * tracking all of our palettes. */
 111
 112        ret = qxl_alloc_bo_reserved(qdev,
 113                                    sizeof(struct qxl_palette) + sizeof(uint32_t) * 2,
 114                                    palette_bo);
 115
 116        ret = qxl_bo_kmap(*palette_bo, (void **)&pal);
 117        pal->num_ents = 2;
 118        pal->unique = unique++;
 119        if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
 120                /* NB: this is the only used branch currently. */
 121                fgcolor = pseudo_palette[fb_image->fg_color];
 122                bgcolor = pseudo_palette[fb_image->bg_color];
 123        } else {
 124                fgcolor = fb_image->fg_color;
 125                bgcolor = fb_image->bg_color;
 126        }
 127        pal->ents[0] = bgcolor;
 128        pal->ents[1] = fgcolor;
 129        qxl_bo_kunmap(*palette_bo);
 130        return 0;
 131}
 132
 133void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
 134                        int stride /* filled in if 0 */)
 135{
 136        struct qxl_device *qdev = qxl_fb_image->qdev;
 137        struct qxl_drawable *drawable;
 138        struct qxl_rect rect;
 139        const struct fb_image *fb_image = &qxl_fb_image->fb_image;
 140        int x = fb_image->dx;
 141        int y = fb_image->dy;
 142        int width = fb_image->width;
 143        int height = fb_image->height;
 144        const char *src = fb_image->data;
 145        int depth = fb_image->depth;
 146        struct qxl_release *release;
 147        struct qxl_bo *image_bo;
 148        struct qxl_image *image;
 149        int ret;
 150
 151        if (stride == 0)
 152                stride = depth * width / 8;
 153
 154        rect.left = x;
 155        rect.right = x + width;
 156        rect.top = y;
 157        rect.bottom = y + height;
 158
 159        ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, &release);
 160        if (ret)
 161                return;
 162
 163        ret = qxl_image_create(qdev, release, &image_bo,
 164                               (const uint8_t *)src, 0, 0,
 165                               width, height, depth, stride);
 166        if (ret) {
 167                qxl_release_unreserve(qdev, release);
 168                qxl_release_free(qdev, release);
 169                return;
 170        }
 171
 172        if (depth == 1) {
 173                struct qxl_bo *palette_bo;
 174                void *ptr;
 175                ret = qxl_palette_create_1bit(&palette_bo, qxl_fb_image);
 176                qxl_release_add_res(qdev, release, palette_bo);
 177
 178                ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0);
 179                image = ptr;
 180                image->u.bitmap.palette =
 181                        qxl_bo_physical_address(qdev, palette_bo, 0);
 182                qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr);
 183                qxl_bo_unreserve(palette_bo);
 184                qxl_bo_unref(&palette_bo);
 185        }
 186
 187        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
 188
 189        drawable->u.copy.src_area.top = 0;
 190        drawable->u.copy.src_area.bottom = height;
 191        drawable->u.copy.src_area.left = 0;
 192        drawable->u.copy.src_area.right = width;
 193
 194        drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
 195        drawable->u.copy.scale_mode = 0;
 196        drawable->u.copy.mask.flags = 0;
 197        drawable->u.copy.mask.pos.x = 0;
 198        drawable->u.copy.mask.pos.y = 0;
 199        drawable->u.copy.mask.bitmap = 0;
 200
 201        drawable->u.copy.src_bitmap =
 202                qxl_bo_physical_address(qdev, image_bo, 0);
 203        qxl_release_unmap(qdev, release, &drawable->release_info);
 204
 205        qxl_release_add_res(qdev, release, image_bo);
 206        qxl_bo_unreserve(image_bo);
 207        qxl_bo_unref(&image_bo);
 208
 209        qxl_fence_releaseable(qdev, release);
 210        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 211        qxl_release_unreserve(qdev, release);
 212}
 213
 214/* push a draw command using the given clipping rectangles as
 215 * the sources from the shadow framebuffer.
 216 *
 217 * Right now implementing with a single draw and a clip list. Clip
 218 * lists are known to be a problem performance wise, this can be solved
 219 * by treating them differently in the server.
 220 */
 221void qxl_draw_dirty_fb(struct qxl_device *qdev,
 222                       struct qxl_framebuffer *qxl_fb,
 223                       struct qxl_bo *bo,
 224                       unsigned flags, unsigned color,
 225                       struct drm_clip_rect *clips,
 226                       unsigned num_clips, int inc)
 227{
 228        /*
 229         * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
 230         * send a fill command instead, much cheaper.
 231         *
 232         * See include/drm/drm_mode.h
 233         */
 234        struct drm_clip_rect *clips_ptr;
 235        int i;
 236        int left, right, top, bottom;
 237        int width, height;
 238        struct qxl_drawable *drawable;
 239        struct qxl_rect drawable_rect;
 240        struct qxl_rect *rects;
 241        int stride = qxl_fb->base.pitches[0];
 242        /* depth is not actually interesting, we don't mask with it */
 243        int depth = qxl_fb->base.bits_per_pixel;
 244        uint8_t *surface_base;
 245        struct qxl_release *release;
 246        struct qxl_bo *image_bo;
 247        struct qxl_bo *clips_bo;
 248        int ret;
 249
 250        left = clips->x1;
 251        right = clips->x2;
 252        top = clips->y1;
 253        bottom = clips->y2;
 254
 255        /* skip the first clip rect */
 256        for (i = 1, clips_ptr = clips + inc;
 257             i < num_clips; i++, clips_ptr += inc) {
 258                left = min_t(int, left, (int)clips_ptr->x1);
 259                right = max_t(int, right, (int)clips_ptr->x2);
 260                top = min_t(int, top, (int)clips_ptr->y1);
 261                bottom = max_t(int, bottom, (int)clips_ptr->y2);
 262        }
 263
 264        width = right - left;
 265        height = bottom - top;
 266        drawable_rect.left = left;
 267        drawable_rect.right = right;
 268        drawable_rect.top = top;
 269        drawable_rect.bottom = bottom;
 270        ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect,
 271                            &release);
 272        if (ret)
 273                return;
 274
 275        ret = qxl_bo_kmap(bo, (void **)&surface_base);
 276        if (ret)
 277                goto out_unref;
 278
 279        ret = qxl_image_create(qdev, release, &image_bo, surface_base,
 280                               left, top, width, height, depth, stride);
 281        qxl_bo_kunmap(bo);
 282        if (ret)
 283                goto out_unref;
 284
 285        rects = drawable_set_clipping(qdev, drawable, num_clips, &clips_bo, release);
 286        if (!rects) {
 287                qxl_bo_unref(&image_bo);
 288                goto out_unref;
 289        }
 290        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
 291
 292        drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
 293        drawable->clip.data = qxl_bo_physical_address(qdev,
 294                                                      clips_bo, 0);
 295        qxl_release_add_res(qdev, release, clips_bo);
 296
 297        drawable->u.copy.src_area.top = 0;
 298        drawable->u.copy.src_area.bottom = height;
 299        drawable->u.copy.src_area.left = 0;
 300        drawable->u.copy.src_area.right = width;
 301
 302        drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
 303        drawable->u.copy.scale_mode = 0;
 304        drawable->u.copy.mask.flags = 0;
 305        drawable->u.copy.mask.pos.x = 0;
 306        drawable->u.copy.mask.pos.y = 0;
 307        drawable->u.copy.mask.bitmap = 0;
 308
 309        drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, image_bo, 0);
 310        qxl_release_unmap(qdev, release, &drawable->release_info);
 311        qxl_release_add_res(qdev, release, image_bo);
 312        qxl_bo_unreserve(image_bo);
 313        qxl_bo_unref(&image_bo);
 314        clips_ptr = clips;
 315        for (i = 0; i < num_clips; i++, clips_ptr += inc) {
 316                rects[i].left   = clips_ptr->x1;
 317                rects[i].right  = clips_ptr->x2;
 318                rects[i].top    = clips_ptr->y1;
 319                rects[i].bottom = clips_ptr->y2;
 320        }
 321        qxl_bo_kunmap(clips_bo);
 322        qxl_bo_unreserve(clips_bo);
 323        qxl_bo_unref(&clips_bo);
 324
 325        qxl_fence_releaseable(qdev, release);
 326        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 327        qxl_release_unreserve(qdev, release);
 328        return;
 329
 330out_unref:
 331        qxl_release_unreserve(qdev, release);
 332        qxl_release_free(qdev, release);
 333}
 334
 335void qxl_draw_copyarea(struct qxl_device *qdev,
 336                       u32 width, u32 height,
 337                       u32 sx, u32 sy,
 338                       u32 dx, u32 dy)
 339{
 340        struct qxl_drawable *drawable;
 341        struct qxl_rect rect;
 342        struct qxl_release *release;
 343        int ret;
 344
 345        rect.left = dx;
 346        rect.top = dy;
 347        rect.right = dx + width;
 348        rect.bottom = dy + height;
 349        ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, &release);
 350        if (ret)
 351                return;
 352
 353        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
 354        drawable->u.copy_bits.src_pos.x = sx;
 355        drawable->u.copy_bits.src_pos.y = sy;
 356
 357        qxl_release_unmap(qdev, release, &drawable->release_info);
 358        qxl_fence_releaseable(qdev, release);
 359        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 360        qxl_release_unreserve(qdev, release);
 361}
 362
 363void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
 364{
 365        struct qxl_device *qdev = qxl_draw_fill_rec->qdev;
 366        struct qxl_rect rect = qxl_draw_fill_rec->rect;
 367        uint32_t color = qxl_draw_fill_rec->color;
 368        uint16_t rop = qxl_draw_fill_rec->rop;
 369        struct qxl_drawable *drawable;
 370        struct qxl_release *release;
 371        int ret;
 372
 373        ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, &release);
 374        if (ret)
 375                return;
 376
 377        drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
 378        drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
 379        drawable->u.fill.brush.u.color = color;
 380        drawable->u.fill.rop_descriptor = rop;
 381        drawable->u.fill.mask.flags = 0;
 382        drawable->u.fill.mask.pos.x = 0;
 383        drawable->u.fill.mask.pos.y = 0;
 384        drawable->u.fill.mask.bitmap = 0;
 385
 386        qxl_release_unmap(qdev, release, &drawable->release_info);
 387        qxl_fence_releaseable(qdev, release);
 388        qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
 389        qxl_release_unreserve(qdev, release);
 390}
 391