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
)
61 ret
= qxl_alloc_release_reserved(qdev
, sizeof(struct qxl_drawable
),
62 QXL_RELEASE_DRAWABLE
, release
,
68 free_drawable(struct qxl_device
*qdev
, struct qxl_release
*release
)
70 qxl_release_free(qdev
, release
);
73 /* release needs to be reserved at this point */
75 make_drawable(struct qxl_device
*qdev
, int surface
, uint8_t type
,
76 const struct qxl_rect
*rect
,
77 struct qxl_release
*release
)
79 struct qxl_drawable
*drawable
;
82 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
86 drawable
->type
= type
;
88 drawable
->surface_id
= surface
; /* Only primary for now */
89 drawable
->effect
= QXL_EFFECT_OPAQUE
;
90 drawable
->self_bitmap
= 0;
91 drawable
->self_bitmap_area
.top
= 0;
92 drawable
->self_bitmap_area
.left
= 0;
93 drawable
->self_bitmap_area
.bottom
= 0;
94 drawable
->self_bitmap_area
.right
= 0;
95 /* FIXME: add clipping */
96 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
99 * surfaces_dest[i] should apparently be filled out with the
100 * surfaces that we depend on, and surface_rects should be
101 * filled with the rectangles of those surfaces that we
104 for (i
= 0; i
< 3; ++i
)
105 drawable
->surfaces_dest
[i
] = -1;
108 drawable
->bbox
= *rect
;
110 drawable
->mm_time
= qdev
->rom
->mm_clock
;
111 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
115 static int alloc_palette_object(struct qxl_device
*qdev
,
116 struct qxl_release
*release
,
117 struct qxl_bo
**palette_bo
)
119 return qxl_alloc_bo_reserved(qdev
, release
,
120 sizeof(struct qxl_palette
) + sizeof(uint32_t) * 2,
124 static int qxl_palette_create_1bit(struct qxl_bo
*palette_bo
,
125 struct qxl_release
*release
,
126 const struct qxl_fb_image
*qxl_fb_image
)
128 const struct fb_image
*fb_image
= &qxl_fb_image
->fb_image
;
129 uint32_t visual
= qxl_fb_image
->visual
;
130 const uint32_t *pseudo_palette
= qxl_fb_image
->pseudo_palette
;
131 struct qxl_palette
*pal
;
133 uint32_t fgcolor
, bgcolor
;
134 static uint64_t unique
; /* we make no attempt to actually set this
135 * correctly globaly, since that would require
136 * tracking all of our palettes. */
137 ret
= qxl_bo_kmap(palette_bo
, (void **)&pal
);
141 pal
->unique
= unique
++;
142 if (visual
== FB_VISUAL_TRUECOLOR
|| visual
== FB_VISUAL_DIRECTCOLOR
) {
143 /* NB: this is the only used branch currently. */
144 fgcolor
= pseudo_palette
[fb_image
->fg_color
];
145 bgcolor
= pseudo_palette
[fb_image
->bg_color
];
147 fgcolor
= fb_image
->fg_color
;
148 bgcolor
= fb_image
->bg_color
;
150 pal
->ents
[0] = bgcolor
;
151 pal
->ents
[1] = fgcolor
;
152 qxl_bo_kunmap(palette_bo
);
156 void qxl_draw_opaque_fb(const struct qxl_fb_image
*qxl_fb_image
,
157 int stride
/* filled in if 0 */)
159 struct qxl_device
*qdev
= qxl_fb_image
->qdev
;
160 struct qxl_drawable
*drawable
;
161 struct qxl_rect rect
;
162 const struct fb_image
*fb_image
= &qxl_fb_image
->fb_image
;
163 int x
= fb_image
->dx
;
164 int y
= fb_image
->dy
;
165 int width
= fb_image
->width
;
166 int height
= fb_image
->height
;
167 const char *src
= fb_image
->data
;
168 int depth
= fb_image
->depth
;
169 struct qxl_release
*release
;
170 struct qxl_image
*image
;
172 struct qxl_drm_image
*dimage
;
173 struct qxl_bo
*palette_bo
= NULL
;
175 stride
= depth
* width
/ 8;
177 ret
= alloc_drawable(qdev
, &release
);
181 ret
= qxl_image_alloc_objects(qdev
, release
,
185 goto out_free_drawable
;
188 ret
= alloc_palette_object(qdev
, release
, &palette_bo
);
193 /* do a reservation run over all the objects we just allocated */
194 ret
= qxl_release_reserve_list(release
, true);
196 goto out_free_palette
;
199 rect
.right
= x
+ width
;
201 rect
.bottom
= y
+ height
;
203 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &rect
, release
);
205 qxl_release_backoff_reserve_list(release
);
206 goto out_free_palette
;
209 ret
= qxl_image_init(qdev
, release
, dimage
,
210 (const uint8_t *)src
, 0, 0,
211 width
, height
, depth
, stride
);
213 qxl_release_backoff_reserve_list(release
);
214 qxl_release_free(qdev
, release
);
220 ret
= qxl_palette_create_1bit(palette_bo
, release
, qxl_fb_image
);
222 ptr
= qxl_bo_kmap_atomic_page(qdev
, dimage
->bo
, 0);
224 image
->u
.bitmap
.palette
=
225 qxl_bo_physical_address(qdev
, palette_bo
, 0);
226 qxl_bo_kunmap_atomic_page(qdev
, dimage
->bo
, ptr
);
229 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
231 drawable
->u
.copy
.src_area
.top
= 0;
232 drawable
->u
.copy
.src_area
.bottom
= height
;
233 drawable
->u
.copy
.src_area
.left
= 0;
234 drawable
->u
.copy
.src_area
.right
= width
;
236 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
237 drawable
->u
.copy
.scale_mode
= 0;
238 drawable
->u
.copy
.mask
.flags
= 0;
239 drawable
->u
.copy
.mask
.pos
.x
= 0;
240 drawable
->u
.copy
.mask
.pos
.y
= 0;
241 drawable
->u
.copy
.mask
.bitmap
= 0;
243 drawable
->u
.copy
.src_bitmap
=
244 qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
245 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
247 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
248 qxl_release_fence_buffer_objects(release
);
252 qxl_bo_unref(&palette_bo
);
254 qxl_image_free_objects(qdev
, dimage
);
257 free_drawable(qdev
, release
);
260 /* push a draw command using the given clipping rectangles as
261 * the sources from the shadow framebuffer.
263 * Right now implementing with a single draw and a clip list. Clip
264 * lists are known to be a problem performance wise, this can be solved
265 * by treating them differently in the server.
267 void qxl_draw_dirty_fb(struct qxl_device
*qdev
,
268 struct qxl_framebuffer
*qxl_fb
,
270 unsigned flags
, unsigned color
,
271 struct drm_clip_rect
*clips
,
272 unsigned num_clips
, int inc
)
275 * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
276 * send a fill command instead, much cheaper.
278 * See include/drm/drm_mode.h
280 struct drm_clip_rect
*clips_ptr
;
282 int left
, right
, top
, bottom
;
284 struct qxl_drawable
*drawable
;
285 struct qxl_rect drawable_rect
;
286 struct qxl_rect
*rects
;
287 int stride
= qxl_fb
->base
.pitches
[0];
288 /* depth is not actually interesting, we don't mask with it */
289 int depth
= qxl_fb
->base
.bits_per_pixel
;
290 uint8_t *surface_base
;
291 struct qxl_release
*release
;
292 struct qxl_bo
*clips_bo
;
293 struct qxl_drm_image
*dimage
;
296 ret
= alloc_drawable(qdev
, &release
);
305 /* skip the first clip rect */
306 for (i
= 1, clips_ptr
= clips
+ inc
;
307 i
< num_clips
; i
++, clips_ptr
+= inc
) {
308 left
= min_t(int, left
, (int)clips_ptr
->x1
);
309 right
= max_t(int, right
, (int)clips_ptr
->x2
);
310 top
= min_t(int, top
, (int)clips_ptr
->y1
);
311 bottom
= max_t(int, bottom
, (int)clips_ptr
->y2
);
314 width
= right
- left
;
315 height
= bottom
- top
;
317 ret
= alloc_clips(qdev
, release
, num_clips
, &clips_bo
);
319 goto out_free_drawable
;
321 ret
= qxl_image_alloc_objects(qdev
, release
,
327 /* do a reservation run over all the objects we just allocated */
328 ret
= qxl_release_reserve_list(release
, true);
332 drawable_rect
.left
= left
;
333 drawable_rect
.right
= right
;
334 drawable_rect
.top
= top
;
335 drawable_rect
.bottom
= bottom
;
337 ret
= make_drawable(qdev
, 0, QXL_DRAW_COPY
, &drawable_rect
,
340 goto out_release_backoff
;
342 ret
= qxl_bo_kmap(bo
, (void **)&surface_base
);
344 goto out_release_backoff
;
347 ret
= qxl_image_init(qdev
, release
, dimage
, surface_base
,
348 left
, top
, width
, height
, depth
, stride
);
351 goto out_release_backoff
;
353 rects
= drawable_set_clipping(qdev
, num_clips
, clips_bo
);
355 goto out_release_backoff
;
357 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
359 drawable
->clip
.type
= SPICE_CLIP_TYPE_RECTS
;
360 drawable
->clip
.data
= qxl_bo_physical_address(qdev
,
363 drawable
->u
.copy
.src_area
.top
= 0;
364 drawable
->u
.copy
.src_area
.bottom
= height
;
365 drawable
->u
.copy
.src_area
.left
= 0;
366 drawable
->u
.copy
.src_area
.right
= width
;
368 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
369 drawable
->u
.copy
.scale_mode
= 0;
370 drawable
->u
.copy
.mask
.flags
= 0;
371 drawable
->u
.copy
.mask
.pos
.x
= 0;
372 drawable
->u
.copy
.mask
.pos
.y
= 0;
373 drawable
->u
.copy
.mask
.bitmap
= 0;
375 drawable
->u
.copy
.src_bitmap
= qxl_bo_physical_address(qdev
, dimage
->bo
, 0);
376 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
379 for (i
= 0; i
< num_clips
; i
++, clips_ptr
+= inc
) {
380 rects
[i
].left
= clips_ptr
->x1
;
381 rects
[i
].right
= clips_ptr
->x2
;
382 rects
[i
].top
= clips_ptr
->y1
;
383 rects
[i
].bottom
= clips_ptr
->y2
;
385 qxl_bo_kunmap(clips_bo
);
387 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
388 qxl_release_fence_buffer_objects(release
);
392 qxl_release_backoff_reserve_list(release
);
394 qxl_image_free_objects(qdev
, dimage
);
396 qxl_bo_unref(&clips_bo
);
398 /* only free drawable on error */
400 free_drawable(qdev
, release
);
404 void qxl_draw_copyarea(struct qxl_device
*qdev
,
405 u32 width
, u32 height
,
409 struct qxl_drawable
*drawable
;
410 struct qxl_rect rect
;
411 struct qxl_release
*release
;
414 ret
= alloc_drawable(qdev
, &release
);
418 /* do a reservation run over all the objects we just allocated */
419 ret
= qxl_release_reserve_list(release
, true);
421 goto out_free_release
;
425 rect
.right
= dx
+ width
;
426 rect
.bottom
= dy
+ height
;
427 ret
= make_drawable(qdev
, 0, QXL_COPY_BITS
, &rect
, release
);
429 qxl_release_backoff_reserve_list(release
);
430 goto out_free_release
;
433 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
434 drawable
->u
.copy_bits
.src_pos
.x
= sx
;
435 drawable
->u
.copy_bits
.src_pos
.y
= sy
;
436 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
438 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
439 qxl_release_fence_buffer_objects(release
);
443 free_drawable(qdev
, release
);
446 void qxl_draw_fill(struct qxl_draw_fill
*qxl_draw_fill_rec
)
448 struct qxl_device
*qdev
= qxl_draw_fill_rec
->qdev
;
449 struct qxl_rect rect
= qxl_draw_fill_rec
->rect
;
450 uint32_t color
= qxl_draw_fill_rec
->color
;
451 uint16_t rop
= qxl_draw_fill_rec
->rop
;
452 struct qxl_drawable
*drawable
;
453 struct qxl_release
*release
;
456 ret
= alloc_drawable(qdev
, &release
);
460 /* do a reservation run over all the objects we just allocated */
461 ret
= qxl_release_reserve_list(release
, true);
463 goto out_free_release
;
465 ret
= make_drawable(qdev
, 0, QXL_DRAW_FILL
, &rect
, release
);
467 qxl_release_backoff_reserve_list(release
);
468 goto out_free_release
;
471 drawable
= (struct qxl_drawable
*)qxl_release_map(qdev
, release
);
472 drawable
->u
.fill
.brush
.type
= SPICE_BRUSH_TYPE_SOLID
;
473 drawable
->u
.fill
.brush
.u
.color
= color
;
474 drawable
->u
.fill
.rop_descriptor
= rop
;
475 drawable
->u
.fill
.mask
.flags
= 0;
476 drawable
->u
.fill
.mask
.pos
.x
= 0;
477 drawable
->u
.fill
.mask
.pos
.y
= 0;
478 drawable
->u
.fill
.mask
.bitmap
= 0;
480 qxl_release_unmap(qdev
, release
, &drawable
->release_info
);
482 qxl_push_command_ring_release(qdev
, release
, QXL_CMD_DRAW
, false);
483 qxl_release_fence_buffer_objects(release
);
487 free_drawable(qdev
, release
);