2 * Copyright 2011 Red Hat, Inc.
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:
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
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.
24 #include "qxl_object.h"
26 static int alloc_clips(struct qxl_device
*qdev
,
27 struct qxl_release
*release
,
29 struct qxl_bo
**clips_bo
)
31 int size
= sizeof(struct qxl_clip_rects
) + sizeof(struct qxl_rect
) * num_clips
;
33 return qxl_alloc_bo_reserved(qdev
, release
, size
, clips_bo
);
36 /* returns a pointer to the already allocated qxl_rect array inside
37 * the qxl_clip_rects. This is *not* the same as the memory allocated
38 * on the device, it is offset to qxl_clip_rects.chunk.data */
39 static struct qxl_rect
*drawable_set_clipping(struct qxl_device
*qdev
,
41 struct qxl_bo
*clips_bo
)
43 struct qxl_clip_rects
*dev_clips
;
46 ret
= qxl_bo_kmap(clips_bo
, (void **)&dev_clips
);
50 dev_clips
->num_rects
= num_clips
;
51 dev_clips
->chunk
.next_chunk
= 0;
52 dev_clips
->chunk
.prev_chunk
= 0;
53 dev_clips
->chunk
.data_size
= sizeof(struct qxl_rect
) * num_clips
;
54 return (struct qxl_rect
*)dev_clips
->chunk
.data
;
58 alloc_drawable(struct qxl_device
*qdev
, struct qxl_release
**release
)
60 return qxl_alloc_release_reserved(qdev
, sizeof(struct qxl_drawable
),
61 QXL_RELEASE_DRAWABLE
, release
, NULL
);
65 free_drawable(struct qxl_device
*qdev
, struct qxl_release
*release
)
67 qxl_release_free(qdev
, release
);
70 /* release needs to be reserved at this point */
72 make_drawable(struct qxl_device
*qdev
, int surface
, uint8_t type
,
73 const struct qxl_rect
*rect
,
74 struct qxl_release
*release
)
76 struct qxl_drawable
*drawable
;
79 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
83 drawable
->type
= type
;
85 drawable
->surface_id
= surface
; /* Only primary for now */
86 drawable
->effect
= QXL_EFFECT_OPAQUE
;
87 drawable
->self_bitmap
= 0;
88 drawable
->self_bitmap_area
.top
= 0;
89 drawable
->self_bitmap_area
.left
= 0;
90 drawable
->self_bitmap_area
.bottom
= 0;
91 drawable
->self_bitmap_area
.right
= 0;
92 /* FIXME: add clipping */
93 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
96 * surfaces_dest[i] should apparently be filled out with the
97 * surfaces that we depend on, and surface_rects should be
98 * filled with the rectangles of those surfaces that we
101 for (i
= 0; i
< 3; ++i
)
102 drawable
->surfaces_dest
[i
] = -1;
105 drawable
->bbox
= *rect
;
107 drawable
->mm_time
= qdev
->rom
->mm_clock
;
108 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
112 static int alloc_palette_object(struct qxl_device
*qdev
,
113 struct qxl_release
*release
,
114 struct qxl_bo
**palette_bo
)
116 return qxl_alloc_bo_reserved(qdev
, release
,
117 sizeof(struct qxl_palette
) + sizeof(uint32_t) * 2,
121 static int qxl_palette_create_1bit(struct qxl_bo
*palette_bo
,
122 struct qxl_release
*release
,
123 const struct qxl_fb_image
*qxl_fb_image
)
125 const struct fb_image
*fb_image
= &qxl_fb_image
->fb_image
;
126 uint32_t visual
= qxl_fb_image
->visual
;
127 const uint32_t *pseudo_palette
= qxl_fb_image
->pseudo_palette
;
128 struct qxl_palette
*pal
;
130 uint32_t fgcolor
, bgcolor
;
131 static uint64_t unique
; /* we make no attempt to actually set this
132 * correctly globaly, since that would require
133 * tracking all of our palettes. */
134 ret
= qxl_bo_kmap(palette_bo
, (void **)&pal
);
138 pal
->unique
= unique
++;
139 if (visual
== FB_VISUAL_TRUECOLOR
|| visual
== FB_VISUAL_DIRECTCOLOR
) {
140 /* NB: this is the only used branch currently. */
141 fgcolor
= pseudo_palette
[fb_image
->fg_color
];
142 bgcolor
= pseudo_palette
[fb_image
->bg_color
];
144 fgcolor
= fb_image
->fg_color
;
145 bgcolor
= fb_image
->bg_color
;
147 pal
->ents
[0] = bgcolor
;
148 pal
->ents
[1] = fgcolor
;
149 qxl_bo_kunmap(palette_bo
);
153 void qxl_draw_opaque_fb(const struct qxl_fb_image
*qxl_fb_image
,
154 int stride
/* filled in if 0 */)
156 struct qxl_device
*qdev
= qxl_fb_image
->qdev
;
157 struct qxl_drawable
*drawable
;
158 struct qxl_rect rect
;
159 const struct fb_image
*fb_image
= &qxl_fb_image
->fb_image
;
160 int x
= fb_image
->dx
;
161 int y
= fb_image
->dy
;
162 int width
= fb_image
->width
;
163 int height
= fb_image
->height
;
164 const char *src
= fb_image
->data
;
165 int depth
= fb_image
->depth
;
166 struct qxl_release
*release
;
167 struct qxl_image
*image
;
169 struct qxl_drm_image
*dimage
;
170 struct qxl_bo
*palette_bo
= NULL
;
172 stride
= depth
* width
/ 8;
174 ret
= alloc_drawable(qdev
, &release
);
178 ret
= qxl_image_alloc_objects(qdev
, release
,
182 goto out_free_drawable
;
185 ret
= alloc_palette_object(qdev
, release
, &palette_bo
);
190 /* do a reservation run over all the objects we just allocated */
191 ret
= qxl_release_reserve_list(release
, true);
193 goto out_free_palette
;
196 rect
.right
= x
+ width
;
198 rect
.bottom
= y
+ height
;
200 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &rect
, release
);
202 qxl_release_backoff_reserve_list(release
);
203 goto out_free_palette
;
206 ret
= qxl_image_init(qdev
, release
, dimage
,
207 (const uint8_t *)src
, 0, 0,
208 width
, height
, depth
, stride
);
210 qxl_release_backoff_reserve_list(release
);
211 qxl_release_free(qdev
, release
);
217 ret
= qxl_palette_create_1bit(palette_bo
, release
, qxl_fb_image
);
219 ptr
= qxl_bo_kmap_atomic_page(qdev
, dimage
->bo
, 0);
221 image
->u
.bitmap
.palette
=
222 qxl_bo_physical_address(qdev
, palette_bo
, 0);
223 qxl_bo_kunmap_atomic_page(qdev
, dimage
->bo
, ptr
);
226 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
228 drawable
->u
.copy
.src_area
.top
= 0;
229 drawable
->u
.copy
.src_area
.bottom
= height
;
230 drawable
->u
.copy
.src_area
.left
= 0;
231 drawable
->u
.copy
.src_area
.right
= width
;
233 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
234 drawable
->u
.copy
.scale_mode
= 0;
235 drawable
->u
.copy
.mask
.flags
= 0;
236 drawable
->u
.copy
.mask
.pos
.x
= 0;
237 drawable
->u
.copy
.mask
.pos
.y
= 0;
238 drawable
->u
.copy
.mask
.bitmap
= 0;
240 drawable
->u
.copy
.src_bitmap
=
241 qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
242 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
244 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
245 qxl_release_fence_buffer_objects(release
);
249 qxl_bo_unref(&palette_bo
);
251 qxl_image_free_objects(qdev
, dimage
);
254 free_drawable(qdev
, release
);
257 /* push a draw command using the given clipping rectangles as
258 * the sources from the shadow framebuffer.
260 * Right now implementing with a single draw and a clip list. Clip
261 * lists are known to be a problem performance wise, this can be solved
262 * by treating them differently in the server.
264 void qxl_draw_dirty_fb(struct qxl_device
*qdev
,
265 struct qxl_framebuffer
*qxl_fb
,
267 unsigned flags
, unsigned color
,
268 struct drm_clip_rect
*clips
,
269 unsigned num_clips
, int inc
)
272 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
273 * send a fill command instead, much cheaper.
275 * See include/drm/drm_mode.h
277 struct drm_clip_rect
*clips_ptr
;
279 int left
, right
, top
, bottom
;
281 struct qxl_drawable
*drawable
;
282 struct qxl_rect drawable_rect
;
283 struct qxl_rect
*rects
;
284 int stride
= qxl_fb
->base
.pitches
[0];
285 /* depth is not actually interesting, we don't mask with it */
286 int depth
= qxl_fb
->base
.bits_per_pixel
;
287 uint8_t *surface_base
;
288 struct qxl_release
*release
;
289 struct qxl_bo
*clips_bo
;
290 struct qxl_drm_image
*dimage
;
293 ret
= alloc_drawable(qdev
, &release
);
302 /* skip the first clip rect */
303 for (i
= 1, clips_ptr
= clips
+ inc
;
304 i
< num_clips
; i
++, clips_ptr
+= inc
) {
305 left
= min_t(int, left
, (int)clips_ptr
->x1
);
306 right
= max_t(int, right
, (int)clips_ptr
->x2
);
307 top
= min_t(int, top
, (int)clips_ptr
->y1
);
308 bottom
= max_t(int, bottom
, (int)clips_ptr
->y2
);
311 width
= right
- left
;
312 height
= bottom
- top
;
314 ret
= alloc_clips(qdev
, release
, num_clips
, &clips_bo
);
316 goto out_free_drawable
;
318 ret
= qxl_image_alloc_objects(qdev
, release
,
324 /* do a reservation run over all the objects we just allocated */
325 ret
= qxl_release_reserve_list(release
, true);
329 drawable_rect
.left
= left
;
330 drawable_rect
.right
= right
;
331 drawable_rect
.top
= top
;
332 drawable_rect
.bottom
= bottom
;
334 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &drawable_rect
,
337 goto out_release_backoff
;
339 ret
= qxl_bo_kmap(bo
, (void **)&surface_base
);
341 goto out_release_backoff
;
344 ret
= qxl_image_init(qdev
, release
, dimage
, surface_base
,
345 left
, top
, width
, height
, depth
, stride
);
348 goto out_release_backoff
;
350 rects
= drawable_set_clipping(qdev
, num_clips
, clips_bo
);
352 goto out_release_backoff
;
354 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
356 drawable
->clip
.type
= SPICE_CLIP_TYPE_RECTS
;
357 drawable
->clip
.data
= qxl_bo_physical_address(qdev
,
360 drawable
->u
.copy
.src_area
.top
= 0;
361 drawable
->u
.copy
.src_area
.bottom
= height
;
362 drawable
->u
.copy
.src_area
.left
= 0;
363 drawable
->u
.copy
.src_area
.right
= width
;
365 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
366 drawable
->u
.copy
.scale_mode
= 0;
367 drawable
->u
.copy
.mask
.flags
= 0;
368 drawable
->u
.copy
.mask
.pos
.x
= 0;
369 drawable
->u
.copy
.mask
.pos
.y
= 0;
370 drawable
->u
.copy
.mask
.bitmap
= 0;
372 drawable
->u
.copy
.src_bitmap
= qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
373 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
376 for (i
= 0; i
< num_clips
; i
++, clips_ptr
+= inc
) {
377 rects
[i
].left
= clips_ptr
->x1
;
378 rects
[i
].right
= clips_ptr
->x2
;
379 rects
[i
].top
= clips_ptr
->y1
;
380 rects
[i
].bottom
= clips_ptr
->y2
;
382 qxl_bo_kunmap(clips_bo
);
384 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
385 qxl_release_fence_buffer_objects(release
);
389 qxl_release_backoff_reserve_list(release
);
391 qxl_image_free_objects(qdev
, dimage
);
393 qxl_bo_unref(&clips_bo
);
395 /* only free drawable on error */
397 free_drawable(qdev
, release
);
401 void qxl_draw_copyarea(struct qxl_device
*qdev
,
402 u32 width
, u32 height
,
406 struct qxl_drawable
*drawable
;
407 struct qxl_rect rect
;
408 struct qxl_release
*release
;
411 ret
= alloc_drawable(qdev
, &release
);
415 /* do a reservation run over all the objects we just allocated */
416 ret
= qxl_release_reserve_list(release
, true);
418 goto out_free_release
;
422 rect
.right
= dx
+ width
;
423 rect
.bottom
= dy
+ height
;
424 ret
= make_drawable(qdev
, 0, QXL_COPY_BITS
, &rect
, release
);
426 qxl_release_backoff_reserve_list(release
);
427 goto out_free_release
;
430 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
431 drawable
->u
.copy_bits
.src_pos
.x
= sx
;
432 drawable
->u
.copy_bits
.src_pos
.y
= sy
;
433 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
435 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
436 qxl_release_fence_buffer_objects(release
);
440 free_drawable(qdev
, release
);
443 void qxl_draw_fill(struct qxl_draw_fill
*qxl_draw_fill_rec
)
445 struct qxl_device
*qdev
= qxl_draw_fill_rec
->qdev
;
446 struct qxl_rect rect
= qxl_draw_fill_rec
->rect
;
447 uint32_t color
= qxl_draw_fill_rec
->color
;
448 uint16_t rop
= qxl_draw_fill_rec
->rop
;
449 struct qxl_drawable
*drawable
;
450 struct qxl_release
*release
;
453 ret
= alloc_drawable(qdev
, &release
);
457 /* do a reservation run over all the objects we just allocated */
458 ret
= qxl_release_reserve_list(release
, true);
460 goto out_free_release
;
462 ret
= make_drawable(qdev
, 0, QXL_DRAW_FILL
, &rect
, release
);
464 qxl_release_backoff_reserve_list(release
);
465 goto out_free_release
;
468 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
469 drawable
->u
.fill
.brush
.type
= SPICE_BRUSH_TYPE_SOLID
;
470 drawable
->u
.fill
.brush
.u
.color
= color
;
471 drawable
->u
.fill
.rop_descriptor
= rop
;
472 drawable
->u
.fill
.mask
.flags
= 0;
473 drawable
->u
.fill
.mask
.pos
.x
= 0;
474 drawable
->u
.fill
.mask
.pos
.y
= 0;
475 drawable
->u
.fill
.mask
.bitmap
= 0;
477 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
479 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
480 qxl_release_fence_buffer_objects(release
);
484 free_drawable(qdev
, release
);