0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
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
0042
0043
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;
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
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;
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
0100 drawable->clip.type = SPICE_CLIP_TYPE_NONE;
0101
0102
0103
0104
0105
0106
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
0120
0121
0122
0123
0124
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
0136
0137
0138
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
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
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
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;
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
0265 if (ret)
0266 free_drawable(qdev, release);
0267
0268 }