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
,
40 struct qxl_drawable
*drawable
,
42 struct qxl_bo
*clips_bo
)
44 struct qxl_clip_rects
*dev_clips
;
47 ret
= qxl_bo_kmap(clips_bo
, (void **)&dev_clips
);
51 dev_clips
->num_rects
= num_clips
;
52 dev_clips
->chunk
.next_chunk
= 0;
53 dev_clips
->chunk
.prev_chunk
= 0;
54 dev_clips
->chunk
.data_size
= sizeof(struct qxl_rect
) * num_clips
;
55 return (struct qxl_rect
*)dev_clips
->chunk
.data
;
59 alloc_drawable(struct qxl_device
*qdev
, struct qxl_release
**release
)
62 ret
= qxl_alloc_release_reserved(qdev
, sizeof(struct qxl_drawable
),
63 QXL_RELEASE_DRAWABLE
, release
,
69 free_drawable(struct qxl_device
*qdev
, struct qxl_release
*release
)
71 qxl_release_free(qdev
, release
);
74 /* release needs to be reserved at this point */
76 make_drawable(struct qxl_device
*qdev
, int surface
, uint8_t type
,
77 const struct qxl_rect
*rect
,
78 struct qxl_release
*release
)
80 struct qxl_drawable
*drawable
;
83 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
87 drawable
->type
= type
;
89 drawable
->surface_id
= surface
; /* Only primary for now */
90 drawable
->effect
= QXL_EFFECT_OPAQUE
;
91 drawable
->self_bitmap
= 0;
92 drawable
->self_bitmap_area
.top
= 0;
93 drawable
->self_bitmap_area
.left
= 0;
94 drawable
->self_bitmap_area
.bottom
= 0;
95 drawable
->self_bitmap_area
.right
= 0;
96 /* FIXME: add clipping */
97 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
100 * surfaces_dest[i] should apparently be filled out with the
101 * surfaces that we depend on, and surface_rects should be
102 * filled with the rectangles of those surfaces that we
105 for (i
= 0; i
< 3; ++i
)
106 drawable
->surfaces_dest
[i
] = -1;
109 drawable
->bbox
= *rect
;
111 drawable
->mm_time
= qdev
->rom
->mm_clock
;
112 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
116 static int alloc_palette_object(struct qxl_device
*qdev
,
117 struct qxl_release
*release
,
118 struct qxl_bo
**palette_bo
)
120 return qxl_alloc_bo_reserved(qdev
, release
,
121 sizeof(struct qxl_palette
) + sizeof(uint32_t) * 2,
125 static int qxl_palette_create_1bit(struct qxl_bo
*palette_bo
,
126 struct qxl_release
*release
,
127 const struct qxl_fb_image
*qxl_fb_image
)
129 const struct fb_image
*fb_image
= &qxl_fb_image
->fb_image
;
130 uint32_t visual
= qxl_fb_image
->visual
;
131 const uint32_t *pseudo_palette
= qxl_fb_image
->pseudo_palette
;
132 struct qxl_palette
*pal
;
134 uint32_t fgcolor
, bgcolor
;
135 static uint64_t unique
; /* we make no attempt to actually set this
136 * correctly globaly, since that would require
137 * tracking all of our palettes. */
138 ret
= qxl_bo_kmap(palette_bo
, (void **)&pal
);
140 pal
->unique
= unique
++;
141 if (visual
== FB_VISUAL_TRUECOLOR
|| visual
== FB_VISUAL_DIRECTCOLOR
) {
142 /* NB: this is the only used branch currently. */
143 fgcolor
= pseudo_palette
[fb_image
->fg_color
];
144 bgcolor
= pseudo_palette
[fb_image
->bg_color
];
146 fgcolor
= fb_image
->fg_color
;
147 bgcolor
= fb_image
->bg_color
;
149 pal
->ents
[0] = bgcolor
;
150 pal
->ents
[1] = fgcolor
;
151 qxl_bo_kunmap(palette_bo
);
155 void qxl_draw_opaque_fb(const struct qxl_fb_image
*qxl_fb_image
,
156 int stride
/* filled in if 0 */)
158 struct qxl_device
*qdev
= qxl_fb_image
->qdev
;
159 struct qxl_drawable
*drawable
;
160 struct qxl_rect rect
;
161 const struct fb_image
*fb_image
= &qxl_fb_image
->fb_image
;
162 int x
= fb_image
->dx
;
163 int y
= fb_image
->dy
;
164 int width
= fb_image
->width
;
165 int height
= fb_image
->height
;
166 const char *src
= fb_image
->data
;
167 int depth
= fb_image
->depth
;
168 struct qxl_release
*release
;
169 struct qxl_image
*image
;
171 struct qxl_drm_image
*dimage
;
172 struct qxl_bo
*palette_bo
= NULL
;
174 stride
= depth
* width
/ 8;
176 ret
= alloc_drawable(qdev
, &release
);
180 ret
= qxl_image_alloc_objects(qdev
, release
,
184 goto out_free_drawable
;
187 ret
= alloc_palette_object(qdev
, release
, &palette_bo
);
192 /* do a reservation run over all the objects we just allocated */
193 ret
= qxl_release_reserve_list(release
, true);
195 goto out_free_palette
;
198 rect
.right
= x
+ width
;
200 rect
.bottom
= y
+ height
;
202 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &rect
, release
);
204 qxl_release_backoff_reserve_list(release
);
205 goto out_free_palette
;
208 ret
= qxl_image_init(qdev
, release
, dimage
,
209 (const uint8_t *)src
, 0, 0,
210 width
, height
, depth
, stride
);
212 qxl_release_backoff_reserve_list(release
);
213 qxl_release_free(qdev
, release
);
219 ret
= qxl_palette_create_1bit(palette_bo
, release
, qxl_fb_image
);
221 ptr
= qxl_bo_kmap_atomic_page(qdev
, dimage
->bo
, 0);
223 image
->u
.bitmap
.palette
=
224 qxl_bo_physical_address(qdev
, palette_bo
, 0);
225 qxl_bo_kunmap_atomic_page(qdev
, dimage
->bo
, ptr
);
228 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
230 drawable
->u
.copy
.src_area
.top
= 0;
231 drawable
->u
.copy
.src_area
.bottom
= height
;
232 drawable
->u
.copy
.src_area
.left
= 0;
233 drawable
->u
.copy
.src_area
.right
= width
;
235 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
236 drawable
->u
.copy
.scale_mode
= 0;
237 drawable
->u
.copy
.mask
.flags
= 0;
238 drawable
->u
.copy
.mask
.pos
.x
= 0;
239 drawable
->u
.copy
.mask
.pos
.y
= 0;
240 drawable
->u
.copy
.mask
.bitmap
= 0;
242 drawable
->u
.copy
.src_bitmap
=
243 qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
244 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
246 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
247 qxl_release_fence_buffer_objects(release
);
251 qxl_bo_unref(&palette_bo
);
253 qxl_image_free_objects(qdev
, dimage
);
256 free_drawable(qdev
, release
);
259 /* push a draw command using the given clipping rectangles as
260 * the sources from the shadow framebuffer.
262 * Right now implementing with a single draw and a clip list. Clip
263 * lists are known to be a problem performance wise, this can be solved
264 * by treating them differently in the server.
266 void qxl_draw_dirty_fb(struct qxl_device
*qdev
,
267 struct qxl_framebuffer
*qxl_fb
,
269 unsigned flags
, unsigned color
,
270 struct drm_clip_rect
*clips
,
271 unsigned num_clips
, int inc
)
274 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
275 * send a fill command instead, much cheaper.
277 * See include/drm/drm_mode.h
279 struct drm_clip_rect
*clips_ptr
;
281 int left
, right
, top
, bottom
;
283 struct qxl_drawable
*drawable
;
284 struct qxl_rect drawable_rect
;
285 struct qxl_rect
*rects
;
286 int stride
= qxl_fb
->base
.pitches
[0];
287 /* depth is not actually interesting, we don't mask with it */
288 int depth
= qxl_fb
->base
.bits_per_pixel
;
289 uint8_t *surface_base
;
290 struct qxl_release
*release
;
291 struct qxl_bo
*clips_bo
;
292 struct qxl_drm_image
*dimage
;
295 ret
= alloc_drawable(qdev
, &release
);
304 /* skip the first clip rect */
305 for (i
= 1, clips_ptr
= clips
+ inc
;
306 i
< num_clips
; i
++, clips_ptr
+= inc
) {
307 left
= min_t(int, left
, (int)clips_ptr
->x1
);
308 right
= max_t(int, right
, (int)clips_ptr
->x2
);
309 top
= min_t(int, top
, (int)clips_ptr
->y1
);
310 bottom
= max_t(int, bottom
, (int)clips_ptr
->y2
);
313 width
= right
- left
;
314 height
= bottom
- top
;
316 ret
= alloc_clips(qdev
, release
, num_clips
, &clips_bo
);
318 goto out_free_drawable
;
320 ret
= qxl_image_alloc_objects(qdev
, release
,
326 /* do a reservation run over all the objects we just allocated */
327 ret
= qxl_release_reserve_list(release
, true);
331 drawable_rect
.left
= left
;
332 drawable_rect
.right
= right
;
333 drawable_rect
.top
= top
;
334 drawable_rect
.bottom
= bottom
;
336 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &drawable_rect
,
339 goto out_release_backoff
;
341 ret
= qxl_bo_kmap(bo
, (void **)&surface_base
);
343 goto out_release_backoff
;
346 ret
= qxl_image_init(qdev
, release
, dimage
, surface_base
,
347 left
, top
, width
, height
, depth
, stride
);
350 goto out_release_backoff
;
352 rects
= drawable_set_clipping(qdev
, drawable
, num_clips
, clips_bo
);
354 goto out_release_backoff
;
356 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
358 drawable
->clip
.type
= SPICE_CLIP_TYPE_RECTS
;
359 drawable
->clip
.data
= qxl_bo_physical_address(qdev
,
362 drawable
->u
.copy
.src_area
.top
= 0;
363 drawable
->u
.copy
.src_area
.bottom
= height
;
364 drawable
->u
.copy
.src_area
.left
= 0;
365 drawable
->u
.copy
.src_area
.right
= width
;
367 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
368 drawable
->u
.copy
.scale_mode
= 0;
369 drawable
->u
.copy
.mask
.flags
= 0;
370 drawable
->u
.copy
.mask
.pos
.x
= 0;
371 drawable
->u
.copy
.mask
.pos
.y
= 0;
372 drawable
->u
.copy
.mask
.bitmap
= 0;
374 drawable
->u
.copy
.src_bitmap
= qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
375 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
378 for (i
= 0; i
< num_clips
; i
++, clips_ptr
+= inc
) {
379 rects
[i
].left
= clips_ptr
->x1
;
380 rects
[i
].right
= clips_ptr
->x2
;
381 rects
[i
].top
= clips_ptr
->y1
;
382 rects
[i
].bottom
= clips_ptr
->y2
;
384 qxl_bo_kunmap(clips_bo
);
386 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
387 qxl_release_fence_buffer_objects(release
);
391 qxl_release_backoff_reserve_list(release
);
393 qxl_image_free_objects(qdev
, dimage
);
395 qxl_bo_unref(&clips_bo
);
397 /* only free drawable on error */
399 free_drawable(qdev
, release
);
403 void qxl_draw_copyarea(struct qxl_device
*qdev
,
404 u32 width
, u32 height
,
408 struct qxl_drawable
*drawable
;
409 struct qxl_rect rect
;
410 struct qxl_release
*release
;
413 ret
= alloc_drawable(qdev
, &release
);
417 /* do a reservation run over all the objects we just allocated */
418 ret
= qxl_release_reserve_list(release
, true);
420 goto out_free_release
;
424 rect
.right
= dx
+ width
;
425 rect
.bottom
= dy
+ height
;
426 ret
= make_drawable(qdev
, 0, QXL_COPY_BITS
, &rect
, release
);
428 qxl_release_backoff_reserve_list(release
);
429 goto out_free_release
;
432 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
433 drawable
->u
.copy_bits
.src_pos
.x
= sx
;
434 drawable
->u
.copy_bits
.src_pos
.y
= sy
;
435 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
437 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
438 qxl_release_fence_buffer_objects(release
);
442 free_drawable(qdev
, release
);
445 void qxl_draw_fill(struct qxl_draw_fill
*qxl_draw_fill_rec
)
447 struct qxl_device
*qdev
= qxl_draw_fill_rec
->qdev
;
448 struct qxl_rect rect
= qxl_draw_fill_rec
->rect
;
449 uint32_t color
= qxl_draw_fill_rec
->color
;
450 uint16_t rop
= qxl_draw_fill_rec
->rop
;
451 struct qxl_drawable
*drawable
;
452 struct qxl_release
*release
;
455 ret
= alloc_drawable(qdev
, &release
);
459 /* do a reservation run over all the objects we just allocated */
460 ret
= qxl_release_reserve_list(release
, true);
462 goto out_free_release
;
464 ret
= make_drawable(qdev
, 0, QXL_DRAW_FILL
, &rect
, release
);
466 qxl_release_backoff_reserve_list(release
);
467 goto out_free_release
;
470 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
471 drawable
->u
.fill
.brush
.type
= SPICE_BRUSH_TYPE_SOLID
;
472 drawable
->u
.fill
.brush
.u
.color
= color
;
473 drawable
->u
.fill
.rop_descriptor
= rop
;
474 drawable
->u
.fill
.mask
.flags
= 0;
475 drawable
->u
.fill
.mask
.pos
.x
= 0;
476 drawable
->u
.fill
.mask
.pos
.y
= 0;
477 drawable
->u
.fill
.mask
.bitmap
= 0;
479 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
481 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
482 qxl_release_fence_buffer_objects(release
);
486 free_drawable(qdev
, release
);