Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2011 Red Hat, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * on the rights to use, copy, modify, merge, publish, distribute, sub
0008  * license, and/or sell copies of the Software, and to permit persons to whom
0009  * the Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
0019  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0020  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0021  */
0022 
0023 #include <linux/iosys-map.h>
0024 
0025 #include <drm/drm_fourcc.h>
0026 #include <drm/drm_framebuffer.h>
0027 
0028 #include "qxl_drv.h"
0029 #include "qxl_object.h"
0030 
0031 static int alloc_clips(struct qxl_device *qdev,
0032                struct qxl_release *release,
0033                unsigned int num_clips,
0034                struct qxl_bo **clips_bo)
0035 {
0036     int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
0037 
0038     return qxl_alloc_bo_reserved(qdev, release, size, clips_bo);
0039 }
0040 
0041 /* returns a pointer to the already allocated qxl_rect array inside
0042  * the qxl_clip_rects. This is *not* the same as the memory allocated
0043  * on the device, it is offset to qxl_clip_rects.chunk.data */
0044 static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
0045                           unsigned int num_clips,
0046                           struct qxl_bo *clips_bo)
0047 {
0048     struct iosys_map map;
0049     struct qxl_clip_rects *dev_clips;
0050     int ret;
0051 
0052     ret = qxl_bo_vmap_locked(clips_bo, &map);
0053     if (ret)
0054         return NULL;
0055     dev_clips = map.vaddr; /* TODO: Use mapping abstraction properly */
0056 
0057     dev_clips->num_rects = num_clips;
0058     dev_clips->chunk.next_chunk = 0;
0059     dev_clips->chunk.prev_chunk = 0;
0060     dev_clips->chunk.data_size = sizeof(struct qxl_rect) * num_clips;
0061     return (struct qxl_rect *)dev_clips->chunk.data;
0062 }
0063 
0064 static int
0065 alloc_drawable(struct qxl_device *qdev, struct qxl_release **release)
0066 {
0067     return qxl_alloc_release_reserved(qdev, sizeof(struct qxl_drawable),
0068                       QXL_RELEASE_DRAWABLE, release, NULL);
0069 }
0070 
0071 static void
0072 free_drawable(struct qxl_device *qdev, struct qxl_release *release)
0073 {
0074     qxl_release_free(qdev, release);
0075 }
0076 
0077 /* release needs to be reserved at this point */
0078 static int
0079 make_drawable(struct qxl_device *qdev, int surface, uint8_t type,
0080           const struct qxl_rect *rect,
0081           struct qxl_release *release)
0082 {
0083     struct qxl_drawable *drawable;
0084     int i;
0085 
0086     drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
0087     if (!drawable)
0088         return -ENOMEM;
0089 
0090     drawable->type = type;
0091 
0092     drawable->surface_id = surface;     /* Only primary for now */
0093     drawable->effect = QXL_EFFECT_OPAQUE;
0094     drawable->self_bitmap = 0;
0095     drawable->self_bitmap_area.top = 0;
0096     drawable->self_bitmap_area.left = 0;
0097     drawable->self_bitmap_area.bottom = 0;
0098     drawable->self_bitmap_area.right = 0;
0099     /* FIXME: add clipping */
0100     drawable->clip.type = SPICE_CLIP_TYPE_NONE;
0101 
0102     /*
0103      * surfaces_dest[i] should apparently be filled out with the
0104      * surfaces that we depend on, and surface_rects should be
0105      * filled with the rectangles of those surfaces that we
0106      * are going to use.
0107      */
0108     for (i = 0; i < 3; ++i)
0109         drawable->surfaces_dest[i] = -1;
0110 
0111     if (rect)
0112         drawable->bbox = *rect;
0113 
0114     drawable->mm_time = qdev->rom->mm_clock;
0115     qxl_release_unmap(qdev, release, &drawable->release_info);
0116     return 0;
0117 }
0118 
0119 /* push a draw command using the given clipping rectangles as
0120  * the sources from the shadow framebuffer.
0121  *
0122  * Right now implementing with a single draw and a clip list. Clip
0123  * lists are known to be a problem performance wise, this can be solved
0124  * by treating them differently in the server.
0125  */
0126 void qxl_draw_dirty_fb(struct qxl_device *qdev,
0127                struct drm_framebuffer *fb,
0128                struct qxl_bo *bo,
0129                unsigned int flags, unsigned int color,
0130                struct drm_clip_rect *clips,
0131                unsigned int num_clips, int inc,
0132                uint32_t dumb_shadow_offset)
0133 {
0134     /*
0135      * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
0136      * send a fill command instead, much cheaper.
0137      *
0138      * See include/drm/drm_mode.h
0139      */
0140     struct drm_clip_rect *clips_ptr;
0141     int i;
0142     int left, right, top, bottom;
0143     int width, height;
0144     struct qxl_drawable *drawable;
0145     struct qxl_rect drawable_rect;
0146     struct qxl_rect *rects;
0147     int stride = fb->pitches[0];
0148     /* depth is not actually interesting, we don't mask with it */
0149     int depth = fb->format->cpp[0] * 8;
0150     struct iosys_map surface_map;
0151     uint8_t *surface_base;
0152     struct qxl_release *release;
0153     struct qxl_bo *clips_bo;
0154     struct qxl_drm_image *dimage;
0155     int ret;
0156 
0157     ret = alloc_drawable(qdev, &release);
0158     if (ret)
0159         return;
0160 
0161     clips->x1 += dumb_shadow_offset;
0162     clips->x2 += dumb_shadow_offset;
0163 
0164     left = clips->x1;
0165     right = clips->x2;
0166     top = clips->y1;
0167     bottom = clips->y2;
0168 
0169     /* skip the first clip rect */
0170     for (i = 1, clips_ptr = clips + inc;
0171          i < num_clips; i++, clips_ptr += inc) {
0172         left = min_t(int, left, (int)clips_ptr->x1);
0173         right = max_t(int, right, (int)clips_ptr->x2);
0174         top = min_t(int, top, (int)clips_ptr->y1);
0175         bottom = max_t(int, bottom, (int)clips_ptr->y2);
0176     }
0177 
0178     width = right - left;
0179     height = bottom - top;
0180 
0181     ret = alloc_clips(qdev, release, num_clips, &clips_bo);
0182     if (ret)
0183         goto out_free_drawable;
0184 
0185     ret = qxl_image_alloc_objects(qdev, release,
0186                       &dimage,
0187                       height, stride);
0188     if (ret)
0189         goto out_free_clips;
0190 
0191     /* do a reservation run over all the objects we just allocated */
0192     ret = qxl_release_reserve_list(release, true);
0193     if (ret)
0194         goto out_free_image;
0195 
0196     drawable_rect.left = left;
0197     drawable_rect.right = right;
0198     drawable_rect.top = top;
0199     drawable_rect.bottom = bottom;
0200 
0201     ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect,
0202                 release);
0203     if (ret)
0204         goto out_release_backoff;
0205 
0206     ret = qxl_bo_vmap_locked(bo, &surface_map);
0207     if (ret)
0208         goto out_release_backoff;
0209     surface_base = surface_map.vaddr; /* TODO: Use mapping abstraction properly */
0210 
0211     ret = qxl_image_init(qdev, release, dimage, surface_base,
0212                  left - dumb_shadow_offset,
0213                  top, width, height, depth, stride);
0214     qxl_bo_vunmap_locked(bo);
0215     if (ret)
0216         goto out_release_backoff;
0217 
0218     rects = drawable_set_clipping(qdev, num_clips, clips_bo);
0219     if (!rects) {
0220         ret = -EINVAL;
0221         goto out_release_backoff;
0222     }
0223     drawable = (struct qxl_drawable *)qxl_release_map(qdev, release);
0224 
0225     drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
0226     drawable->clip.data = qxl_bo_physical_address(qdev,
0227                               clips_bo, 0);
0228 
0229     drawable->u.copy.src_area.top = 0;
0230     drawable->u.copy.src_area.bottom = height;
0231     drawable->u.copy.src_area.left = 0;
0232     drawable->u.copy.src_area.right = width;
0233 
0234     drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
0235     drawable->u.copy.scale_mode = 0;
0236     drawable->u.copy.mask.flags = 0;
0237     drawable->u.copy.mask.pos.x = 0;
0238     drawable->u.copy.mask.pos.y = 0;
0239     drawable->u.copy.mask.bitmap = 0;
0240 
0241     drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, dimage->bo, 0);
0242     qxl_release_unmap(qdev, release, &drawable->release_info);
0243 
0244     clips_ptr = clips;
0245     for (i = 0; i < num_clips; i++, clips_ptr += inc) {
0246         rects[i].left   = clips_ptr->x1;
0247         rects[i].right  = clips_ptr->x2;
0248         rects[i].top    = clips_ptr->y1;
0249         rects[i].bottom = clips_ptr->y2;
0250     }
0251     qxl_bo_vunmap_locked(clips_bo);
0252 
0253     qxl_release_fence_buffer_objects(release);
0254     qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
0255 
0256 out_release_backoff:
0257     if (ret)
0258         qxl_release_backoff_reserve_list(release);
0259 out_free_image:
0260     qxl_image_free_objects(qdev, dimage);
0261 out_free_clips:
0262     qxl_bo_unref(&clips_bo);
0263 out_free_drawable:
0264     /* only free drawable on error */
0265     if (ret)
0266         free_drawable(qdev, release);
0267 
0268 }